# 使用指南 ***Copyright © Quectel Wireless Solutions Co., Ltd. 2026. All rights reserved.*** --- 本文档介绍 **Quectel Pi H1** 智能主控板的常用功能和使用方法,包括音频与多媒体、机器学习、系统配置与监控、40-pin与接口扩展、网络与通信、图形与显示、摄像头方案、存储设备、核心资源与性能、电源与功耗、USB与扩展外设等内容。 # 音频与多媒体 ## PulseAudio音频服务 PulseAudio是Linux环境下主流的音频服务系统,它介于应用程序和底层音频架构(TinyALSA)之间,负责管理音频流、混合多路音频以及路由到不同的输出设备。 ## PulseAudio概述 PulseAudio是一个跨平台的、可通过网络工作的声音服务,它从一个或多个音源(进程或输入设备)接受声音输入,然后重定向声音到一个或多个槽(声卡,远程网络PulseAudio服务,或其他进程)。它与最底层的ALSA(Advanced Linux Sound Architecture)交互,并为应用程序提供统一的接口,从而实现多路音频混合、音频转发等高级功能。 ## 查看声卡信息 在终端中输入如下命令,查看声卡的挂载情况: ```shell root@qcm6490-idp:/opt# cat /proc/asound/cards0 [qcm6490idpsndca]: qcm6490 - qcm6490-idp-snd-card qcm6490-idp-snd-card ``` ## 设备查看与管理 ### 查看可用输出设备(Sinks) 如需查看系统当前可用的音频输出设备及其详细信息,可以使用以下命令,此命令会列出所有可用的sink(输出设备)的索引(index)和名称(name)。输出示例: ```bash root@qcm6490-idp:/# pactl list short sinks * 0 low-latency0 module-pal-card.c s16le 1ch 16000Hz SUSPENDED 1 deep-buffer0 module-pal-card.c s16le 2ch 48000Hz SUSPENDED 2 offload0 module-pal-card.c s16le 2ch 48000Hz SUSPENDED 3 voip-rx0 module-pal-card.c s16le 2ch 48000Hz SUSPENDED ``` 其中,*号标记表示当前默认的输出设备。 如需获取更详细的设备信息,请使用: ```bash root@qcm6490-idp:/# pactl list sinks Sink #0 State: SUSPENDED Name: low-latency0 Description: pal sink to play via low-latency path Driver: module-pal-card.c Sample Specification: s16le 1ch 16000Hz Channel Map: mono Owner Module: 1 Mute: no Volume: mono: 65536 / 100% balance 0.00 Base Volume: 65536 / 100% Monitor Source: low-latency0.monitor Latency: 0 usec, configured 0 usec Flags: HARDWARE HW_VOLUME_CTRL LATENCY Properties: device.string = "low_latency" device.description = "pal sink to play via low-latency path" device.icon_name = "audio-card" Ports: speaker: speaker (type: Unknown, priority: 200, available) headset: headset (type: Unknown, priority: 100, available) Active Port: speaker Formats: pcm Sink #1 State: SUSPENDED Name: deep-buffer0 Description: pal sink to play via deep buffer path Driver: module-pal-card.c Sample Specification: s16le 2ch 48000Hz Channel Map: front-left,front-right Owner Module: 1 Mute: no Volume: front-left: 65536 / 100%, front-right: 65536 / 100% balance 0.00 Base Volume: 65536 / 100% Monitor Source: deep-buffer0.monitor Latency: 0 usec, configured 0 usec Flags: HARDWARE HW_VOLUME_CTRL LATENCY Properties: device.string = "deep_buffer" device.description = "pal sink to play via deep buffer path" device.icon_name = "audio-card" Ports: speaker: speaker (type: Unknown, priority: 200, available) headset: headset (type: Unknown, priority: 100, available) bta2dp-out: BT a2dp source port (type: Unknown, priority: 50, not available) Active Port: speaker Formats: pcm Sink #2 State: SUSPENDED Name: offload0 Description: pal sink to play compressed via offload path Driver: module-pal-card.c Sample Specification: s16le 2ch 48000Hz Channel Map: front-left,front-right Owner Module: 1 Mute: no Volume: front-left: 65536 / 100%, front-right: 65536 / 100% balance 0.00 Base Volume: 65536 / 100% Monitor Source: offload0.monitor Latency: 0 usec, configured 0 usec Flags: HARDWARE HW_VOLUME_CTRL LATENCY Properties: device.string = "offload" device.description = "pal sink to play compressed via offload path" device.icon_name = "audio-card" Ports: speaker: speaker (type: Unknown, priority: 200, available) headset: headset (type: Unknown, priority: 100, available) bta2dp-out: BT a2dp source port (type: Unknown, priority: 50, not available) Active Port: speaker Formats: mpeg aac Sink #3 State: SUSPENDED Name: voip-rx0 Description: pal sink to play via voip rx path Driver: module-pal-card.c Sample Specification: s16le 2ch 48000Hz Channel Map: front-left,front-right Owner Module: 1 Mute: no Volume: front-left: 65536 / 100%, front-right: 65536 / 100% balance 0.00 Base Volume: 65536 / 100% Monitor Source: voip-rx0.monitor Latency: 0 usec, configured 0 usec Flags: HARDWARE HW_VOLUME_CTRL LATENCY Properties: device.string = "voip_rx" device.description = "pal sink to play via voip rx path" device.icon_name = "audio-card" Ports: speaker: speaker (type: Unknown, priority: 200, available) headset: headset (type: Unknown, priority: 100, available) btsco-out: BT SCO sink port (type: Unknown, priority: 50, not available) Active Port: speaker Formats: pcm ``` ### 查看输入设备(Sources) 类似地,可以查看音频输入设备(如麦克风): ```bash root@qcm6490-idp:/# pactl list short sources0 low-latency0.monitor module-pal-card.c s16le 1ch 16000Hz SUSPENDED 1 deep-buffer0.monitor module-pal-card.c s16le 2ch 48000Hz SUSPENDED 2 offload0.monitor module-pal-card.c s16le 2ch 48000Hz SUSPENDED 3 voip-rx0.monitor module-pal-card.c s16le 2ch 48000Hz SUSPENDED 4 regular0 module-pal-card.c s16le 2ch 48000Hz SUSPENDED 5 regular2 module-pal-card.c s16le 2ch 48000Hz SUSPENDED 6 voip-tx0 module-pal-card.c s16le 1ch 48000Hz SUSPENDED ``` ## 录音 ### 板载DMIC录音 ```bash root@qcm6490-idp:~# pactl set-source-port 5 speaker-mic root@qcm6490-idp:~# parec -d 5 --file-format=wav output.wav ``` ### 3.5 mm耳机录音 使用3.5 mm耳机录制前需将gpio8和gpio68电平置高。 ```shell root@qcm6490-idp:/opt# rgpiod & root@qcm6490-idp:/opt# sleep 1 root@qcm6490-idp:/opt# rgs c 999 go 4 root@qcm6490-idp:/opt# rgs c 999 gso 0 8 root@qcm6490-idp:/opt# rgs c 999 gw 0 8 1 root@qcm6490-idp:/opt# rgs c 999 gso 0 68 root@qcm6490-idp:/opt# rgs c 999 gw 0 68 1 ``` - **gpio8**:耳机欧标/美标切换控制开关。0:欧标;1:美标 - **gpio68**:耳机电源供电使能开关。0:禁用;1:使能 ```bash root@qcm6490-idp:~# pactl set-source-port 5 headset-mic root@qcm6490-idp:~# parec -d 5 --file-format=wav output1.wav ``` ## 播放 ### 喇叭播放 GPIO控制PA的使能开关: ```shell rgpiod &sleep 1 rgs c 999 go 4 rgs c 999 gso 0 142 rgs c 999 gw 0 142 1 ``` ```bash root@qcm6490-idp:~# pactl set-sink-port 0 speaker root@qcm6490-idp:~# paplay output.wav ``` ### 3.5 mm耳机播放 ```bash root@qcm6490-idp:~# pactl set-sink-port 0 headset root@qcm6490-idp:~# paplay output1.wav ``` ## TinyALSA/AGM直连音频测试 **Quectel Pi H1** 智能主控板支持外置MIC录制、3.5 mm耳机录制与播放等多种直连音频链路,以下示例基于TinyALSA/AGM工具链说明如何直接访问声卡。 ### 查看声卡信息 - 在终端中输入如下命令,查看声卡的挂载情况: ```shell root@qcm6490-idp:/opt# cat /proc/asound/cards0 [qcm6490idpsndca]: qcm6490 - qcm6490-idp-snd-card qcm6490-idp-snd-card ``` - 在终端中输入如下命令,查看已分配的PCM流列表: ```shell root@qcm6490-idp:/opt# cat /proc/asound/pcm 00-00: CODEC_DMA-LPAIF_RXTX-RX-0 multicodec-0 : : playback 1 00-01: CODEC_DMA-LPAIF_RXTX-TX-3 multicodec-1 : : capture 1 00-02: CODEC_DMA-LPAIF_VA-TX-0 va_macro_tx1-2 : : capture 1 ``` ### 外置MIC录制 1. 停止PulseAudio避免占用音频设备,并设置采集链路: ```shell root@qcm6490-idp:/opt# systemctl stop pulseaudio root@qcm6490-idp:/opt# tinymix set "VA DMIC MUX0" "DMIC0" root@qcm6490-idp:/opt# tinymix set "VA_AIF1_CAP Mixer DEC0" "1" root@qcm6490-idp:/opt# tinymix set "VA_DEC0 Volume" "100" root@qcm6490-idp:/opt# agmcap test1.wav -D 100 -d 101 -c 1 -r 48000 -b 16 -i "CODEC_DMA-LPAIF_VA-TX-0" ``` - *-c 1*:单声道录音 - *-r 48000*:采样率48 kHz - *-b 16*:采样位深16-bit - *-i "CODEC_DMA-LPAIF_VA-TX-0"*:指定输入设备接口 2. 按 *Ctrl+C* 停止录制,当前目录生成 *test1.wav* 文件: ```shell root@qcm6490-idp:/opt# ls cni containerd test1.wav ``` ### 3.5 mm耳机录制 1. 将 *gpio8*、*gpio68* 置高,打开耳机标准切换与电源: ```shell root@qcm6490-idp:/opt# rgpiod & root@qcm6490-idp:/opt# sleep 1 root@qcm6490-idp:/opt# rgs c 999 go 4 root@qcm6490-idp:/opt# rgs c 999 gso 0 8 root@qcm6490-idp:/opt# rgs c 999 gw 0 8 1 root@qcm6490-idp:/opt# rgs c 999 gso 0 68 root@qcm6490-idp:/opt# rgs c 999 gw 0 68 1 ``` 2. 配置录制链路并开始采集: ```shell root@qcm6490-idp:/opt# systemctl stop pulseaudio root@qcm6490-idp:/opt# tinymix set "TX DEC0 MUX" "SWR_MIC" root@qcm6490-idp:/opt# tinymix set "TX SMIC MUX0" "ADC1" root@qcm6490-idp:/opt# tinymix set "TX_AIF1_CAP Mixer DEC0" "1" root@qcm6490-idp:/opt# tinymix set "ADC2 MUX" "INP2" root@qcm6490-idp:/opt# tinymix set "ADC2 Switch" "1" root@qcm6490-idp:/opt# tinymix set "ADC2_MIXER Switch" "1" root@qcm6490-idp:/opt# tinymix set "TX_DEC0 Volume" "80" root@qcm6490-idp:/opt# tinymix set "ADC2 Volume" "20" root@qcm6490-idp:/opt# agmcap test2.wav -D 100 -d 101 -c 1 -r 48000 -b 16 -i "CODEC_DMA-LPAIF_RXTX-TX-3" ``` 3. 按 *Ctrl+C* 停止录制,*test2.wav* 文件生成在当前目录: ```shell root@qcm6490-idp:/opt# ls cni containerd test2.wav ``` ### 3.5 mm耳机播放 1. 同样先拉高 *gpio8*、*gpio68* 以启用耳机: ```shell root@qcm6490-idp:/opt# rgpiod & root@qcm6490-idp:/opt# sleep 1 root@qcm6490-idp:/opt# rgs c 999 go 4 root@qcm6490-idp:/opt# rgs c 999 gso 0 8 root@qcm6490-idp:/opt# rgs c 999 gw 0 8 1 root@qcm6490-idp:/opt# rgs c 999 gso 0 68 root@qcm6490-idp:/opt# rgs c 999 gw 0 68 1 ``` 2. 设置播放路径并使用 *agmplay* 输出音频: ```shell root@qcm6490-idp:/opt# systemctl stop pulseaudio root@qcm6490-idp:/opt# tinymix set "RX_MACRO RX0 MUX" "AIF1_PB" root@qcm6490-idp:/opt# tinymix set "RX_MACRO RX1 MUX" "AIF1_PB" root@qcm6490-idp:/opt# tinymix set "RX INT0_1 MIX1 INP0" "RX0" root@qcm6490-idp:/opt# tinymix set "RX INT1_1 MIX1 INP0" "RX1" root@qcm6490-idp:/opt# tinymix set "RX INT0 DEM MUX" "CLSH_DSM_OUT" root@qcm6490-idp:/opt# tinymix set "RX INT1 DEM MUX" "CLSH_DSM_OUT" root@qcm6490-idp:/opt# tinymix set "RX_COMP1 Switch" "1" root@qcm6490-idp:/opt# tinymix set "RX_COMP2 Switch" "1" root@qcm6490-idp:/opt# tinymix set "HPHL Switch" "1" root@qcm6490-idp:/opt# tinymix set "HPHR Switch" "1" root@qcm6490-idp:/opt# tinymix set "HPHL_RDAC Switch" "1" root@qcm6490-idp:/opt# tinymix set "HPHR_RDAC Switch" "1" root@qcm6490-idp:/opt# agmplay test.wav -D 100 -d 100 -i "CODEC_DMA-LPAIF_RXTX-RX-0" ``` - 音频播放完会自动停止,若想提前停止,可按 *Ctrl+C*。 --- # 机器学习 ## NPU应用场景 在 **Quectel Pi H1** 智能主控板中,**NPU** 资源应用场景包括:图像分类、目标检测、语义分割等。该章节以图像分类中的 **ResNeXt50** 机器学习模型为例,该模型可以对 **Imagenet** 数据集中的图像进行分类,也可以作为构建更复杂模型的主干,用于特定用例。 ## 下载量化模型 - [ResNeXt50量化]() - [标签文件]() ## 部署模型 1. 将模型和标签文件部署到 **Quectel Pi H1** 中,通过 **adb** 或者 **scp** 把这两个部署到 **/opt** 目录下。 2. 模型特性: - 模型检查点:**Imagenet** - 输入分辨率:**224 x 224** - 参数数量:**88.7 M** - 模型大小:**87.3 MB** ## 连接显示器 准备显示器,并连接显示器到 **Quectel Pi H1** 上。 ## 运行命令 在设备终端运行如下命令以确保结果显示在连接的显示器上: ```bash export XDG_RUNTIME_DIR=/dev/socket/weston && export WAYLAND_DISPLAY=wayland-1 ``` 在设备中运行以下命令: ```bash gst-launch-1.0 -e --gst-debug=2 filesrc location=/opt/video11.mp4 ! qtdemux ! queue ! h264parse ! v4l2h264dec capture-io-mode=5 output-io-mode=5 ! queue ! tee name=split split. ! queue ! qtivcomposer name=mixer sink_1::position="<30, 30>" sink_1::dimensions="<640, 360>" ! queue ! waylandsink sync=true fullscreen=true split. ! queue ! qtimlvconverter ! queue ! qtimltflite delegate=external external-delegate-path=libQnnTFLiteDelegate.so external-delegate-options="QNNExternalDelegate,backend_type=htp;" model=/opt/resnext50_quantized.tflite ! queue ! qtimlvclassification threshold=35.0 results=5 module=mobilenet labels=/opt/imagenet_labels.txt extra-operation=softmax constants="Resnetnet,q-offsets=<30.0>,q-scales=<0.06314703077077866>;" ! video/x-raw,format=BGRA,width=256,height=144 ! queue ! mixer. ``` ### 命令说明 - **gst-launch-1.0**:这是 **GStreamer** 的命令行工具,用于启动一个GStreamer管道(pipeline)。其后的 **-e** 参数表示在管道结束时退出,而不是继续运行。 - **--gst-debug=2**:设置调试级别为2,显示调试信息。 - **filesrc location=/opt/video11.mp4**:指定输入视频文件路径。 - **!**:是一个连接符号,用于将前一个元素的输出连接到后一个元素的输入。 - **qtdemux**:将输入视频文件解析为多个流。 - **queue**:用于缓冲输入数据。 - **h264parse**:将输入数据解析为H.264格式数据。 - **v4l2h264dec**:将H.264格式的数据解码为YUV格式。 - **capture-io-mode=5**:指定解码器输入端口(Capture Side)的内存访问模式。 - **output-io-mode=5**:指定解码器输出端口(Output Side)的内存访问模式。 - **tee name=split**:将输入数据分割为两个分支。 - **split.**:第一个分支用于显示原始视频流。 - **qtivcomposer**:用于组合多个视频流。 - **waylandsink**:将组合后的视频流显示在屏幕上。 - **split.**:第二个分支用于进行图像分类。 - **qtimlvconverter**:用于将输入数据转换为模型输入格式。 - **qtimltflite**:用于执行模型推理。 - **delegate=external**:使用外部加速库(即非TFLite默认的CPU后端)来运行模型推理,通常用于调用硬件加速器。 - **external-delegate-path=libQnnTFLiteDelegate.so**:指定TensorFlow Lite的外部加速库(Delegate)的路径。 - **external-delegate-options="QNNExternalDelegate,backend_type=htp;"**:指定外部加速库的选项,这里指定了后端类型为HTP(High-Throughput Processing)。 - **model=/opt/resnext50_quantized.tflite**:指定模型路径。 - **qtimlvclassification**:用于对模型输出进行分类。 - **video/x-raw,format=BGRA,width=256,height=144**:指定输出视频格式和尺寸。 - **mixer**:将两个分支的输出组合在一起。 - **threshold=35.0**:设置置信度阈值,用于过滤低置信度的分类结果。 - **results=5**:设置返回的分类结果数量。 - **module=mobilenet**:指定使用的模型名称。 - **labels=/opt/imagenet_labels.txt**:指定标签文件路径。 - **extra-operation=softmax**:对模型输出进行Softmax操作,得到每个类别的概率。 - **constants="Resnetnet,q-offsets=<30.0>,q-scales=<0.06314703077077866>;"**:指定模型量化参数。 ## 运行结果 运行命令后,显示器会显示视频流和图像分类结果。 ```{image} images/image_Pw7NbjlwVocV2kxFR7ocsC2en7b.webp :width: 1280px :height: 720px ``` ## TensorFlow Lite简介 **TensorFlow Lite** 是一套工具,通过帮助开发人员在移动设备、嵌入式设备和边缘设备上运行模型,实现设备机器学习。下面以姿态估计中的 **posenet** 机器学习模型为例,演示实时推理与显示流程。 ### 下载posenet模型 - [posenet_mobilenet]() ### 部署模型 1. 将模型和标签文件部署到 **Quectel Pi H1** 中,通过 **adb** 或者 **scp** 把文件放在 **/opt/** 目录。 2. 模型特性: - 模型检查点:**mobilenet_v1_101** - 输入分辨率:**513 x 257** - 参数数量:**3.31 M** - 模型大小:**12.7 MB** ### 连接摄像头和显示器 - 准备 **MIPI** 摄像头,并连接到第一个 **CSI** 插槽。 - 准备 **HDMI** 显示器,并连接至开发板。 ### 使用TFLite进行姿势估计和显示 1. 设置Wayland环境变量: ```bash export XDG_RUNTIME_DIR=/dev/socket/weston && export WAYLAND_DISPLAY=wayland-1 ``` 2. 启动实时姿势估计: ```bash setprop persist.overlay.use_c2d_blit 2 gst-launch-1.0 -e \ qtiqmmfsrc name=camsrc camera=0 ! video/x-raw\(memory:GBM\),format=NV12,width=1280,height=720,framerate=30/1,compression=ubwc ! queue ! tee name=split \ split. ! queue ! qtimetamux name=metamux ! queue ! qtioverlay ! queue ! waylandsink fullscreen=true sync=false \ split. ! queue ! qtimlvconverter ! queue ! qtimltflite delegate=external external-delegate-path=libQnnTFLiteDelegate.so external-delegate-options="QNNExternalDelegate,backend_type=htp;" model=/opt/posenet_mobilenet_v1.tflite ! queue ! qtimlvpose threshold=51.0 results=2 module=posenet labels=/opt/posenet_mobilenet_v1.labels constants="Posenet,q-offsets=<128.0,128.0,117.0>,q-scales=<0.0784313753247261,0.0784313753247261,1.3875764608383179>;" ! text/x-raw ! queue ! metamux. ``` ### 关键命令说明 - **gst-launch-1.0**:构建GStreamer pipeline,*-e* 确保结束时释放资源。 - **qtiqmmfsrc**:基于 **QMMF** 的摄像头源,*camera=0* 选择第一个CSI接口。 - **tee name=split**:复制原始视频流,分别用于显示与推理。 - **qtimlvconverter**:将 **NV12** 视频帧转换成模型输入张量。 - **qtimltflite**:调用 **TensorFlow Lite** + **QNN delegate**,以HTP加速模型推理。 - **qtimlvpose**:对推理结果做姿态解码并输出人体关键点。 - **qtioverlay/qtimetamux**:将关键点叠加到视频帧并通过 *waylandsink* 输出。 ### 运行结果 运行命令后,显示器会显示camera流和姿势估计结果。
pose_det
--- # 系统配置与监控 qpi_config是一个用于配置 **Quectel Pi H1** 的工具,提供下列功能: 1. 配置板载LED工作模式和亮度; 2. 配置风扇接口工作模式和风扇转速; 3. 配置40-Pin接口工作模式; 4. 查询系统各组件温度; 5. 查询系统CPU、内存和存储状态; 6. 配置Wi-Fi。 ## 板载LED配置 ### 配置工作模式 ```shell qpi-config led mode ``` ### 配置亮度 ```shell qpi-config led brightness <0-511> ``` ## 风扇配置 ### 配置风扇转速 ```shell qpi-config fan set speed <0-255> ``` ## 40-Pin接口工作模式配置 先修改配置文件 */etc/qpi-config/qpi-config.ini*,再运行以下命令进行配置: ```shell qpi-config 40pin set ``` ## 查询系统各组件温度 ```shell qpi-config dump temperature ``` ## 查询系统CPU、内存和存储状态 ```shell qpi-config dump systemusage ``` ## 配置Wi-Fi ### 扫描Wi-Fi ```shell qpi-config wifi scan ``` ### 查看已存在Wi-Fi连接 ```shell qpi-config wifi show ``` ### 查看Wi-Fi连接状态 ```shell qpi-config wifi dump ``` ### 添加Wi-Fi连接 ```shell qpi-config wifi connect ``` ### 删除Wi-Fi连接 ```shell qpi-config wifi delete ``` --- # 40PIN与接口扩展 ```{image} images/image_LX76bZyhwofim5xbStDcct8lnTc.webp :width: 1287px :height: 768px ``` ```{image} images/image_GcORbYCPvojZ9axlISnc1N7fnUe.webp :width: 1287px :height: 694px ``` **40-Pin中部分低速接口(I2C9/SPI10/UART12_2w/I2C13/SPI14)配置文件位于/etc/qpi-config/qpi-config.ini,配置步骤为:** 1. 修改 **qpi-config.ini** 配置 2. 应用配置 ```shell qpi-config 40pin set ``` 3. 重启生效 ## GPIO测试 选取一个 **40-pin** 的 **GPIO** 引脚来测试 **GPIO** 功能,例如选取 **40-pin** 的 **Pin3** 引脚进行测试,**pin3** 对应的 **gpio_num** 为 **36**。各引脚对应的 **gpio_num** 信息可以从引脚映射表中查找。 连接示意图如下,其中红色线接万用表正极,白色线接万用表负极: ```{image} images/image_ZbaUbLlFwocirex9sPbcv3kAn1c.webp :width: 3264px :height: 2252px ``` ### 使用Shell命令控制 系统已默认启用 **lgpiod** 服务,依次执行如下命令来测试 **40-pin** 的 **Pin3** 引脚的 **GPIO** 功能: - *rgs c 999 go 4* #使用 **go** 命令打开文件 **/dev/gpiochip4** - *rgs c 999 gso 0 36* #使用 **gso** 命令设置 **GPIO36** 为输出模式,这条命令里的 **0** 是上一条命令的返回内容,根据实际情况修改 - *rgs c 999 gw 0 36 0* #设置 **GPIO36** 为低电平,这个时候测试引脚电压值为 **0 V** - *rgs c 999 gw 0 36 1* #设置 **GPIO36** 为高电平,这个时候测试引脚电压值为 **3.3 V** ### 使用C代码控制 - 新建 **gpio.c** 文件,内容如下: ```c #include #include int main(int argc, char **argv){int gpio_num = atoi(argv[1]);int pin_level = atoi(argv[2]);int handle = lgGpiochipOpen(4);lgGpioClaimOutput(handle, 0, gpio_num, 0);lgGpioWrite(handle, gpio_num, pin_level);} ``` - 编译:**gcc -o gpio gpio.c -llgpio** - 执行:**./gpio 36 0** #设置 **GPIO36** 为低电平,这个时候测试引脚电压值为 **0 V** - 执行:**./gpio 36 1** #设置 **GPIO36** 为高电平,这个时候测试引脚电压值为 **3.3 V** ## I2C测试 **40-Pin** 的 **Pin3** 和 **Pin5** 默认是 **I2C** 的 **data** 和 **clock** 引脚,对应设备节点 **/dev/i2c9**,若节点未出现,您可以先使用本章介绍的 **qpi_config** 进行配置和使能。 测试 **I2C** 接口需要外接一个 **I2C** 设备,这里选择微雪环境传感器扩展板,通过 **40-Pin** 接口进行连接。 连接示意图: ```{image} images/image_JqljbxHRFom9RjxnK09c0pIdnje.webp :width: 1706px :height: 1280px ```
微雪环境传感器扩展板
```{image} images/image_NNGAb0qszoxIxRxs6MucgUzOnsg.webp :width: 1706px :height: 1280px ```
Quectel Pi H1 40-PIN引脚
```{image} images/image_VdlubeIXxo4in5xf3G6ccRMCncb.webp :width: 1706px :height: 1280px ```
插上环境传感器扩展板的Quectel Pi H1
### 使用C代码测试 测试步骤: - 新建 **envtest.c** 文件,内容如下: ```c #include #include #define I2C_DEV_NUM 9#define BME280_ADDR 0x76int32_t digT[3],digP[9],digH[6];int32_t t_fine = 0.0;double compensate_P(int32_t adc_P){double pressure = 0.0;double v1,v2; v1 = (t_fine / 2.0) - 64000.0; v2 = (((v1 / 4.0) * (v1 / 4.0)) / 2048) * digP[5]; v2 = v2 + ((v1 * digP[4]) * 2.0); v2 = (v2 / 4.0) + (digP[3] * 65536.0); v1 = (((digP[2] * (((v1 / 4.0) * (v1 / 4.0)) / 8192)) / 8) + ((digP[1] * v1) / 2.0)) / 262144; v1 = ((32768 + v1) * digP[0]) / 32768;if(v1 == 0)return 0; pressure = ((1048576 - adc_P) - (v2 / 4096)) * 3125;if (pressure < 0x80000000) pressure = (pressure * 2.0) / v1;else pressure = (pressure / v1) * 2; v1 = (digP[8] * (((pressure / 8.0) * (pressure / 8.0)) / 8192.0)) / 4096; v2 = ((pressure / 4.0) * digP[7]) / 8192.0; pressure = pressure + ((v1 + v2 + digP[6]) / 16.0) ;return (pressure/100);}double compensate_T(int32_t adc_T){double temperature = 0.0;double v1,v2; v1 = (adc_T / 16384.0 - digT[0] / 1024.0) * digT[1]; v2 = (adc_T / 131072.0 - digT[0] / 8192.0) * (adc_T / 131072.0 - digT[0] / 8192.0) * digT[2]; t_fine = v1 + v2; temperature = t_fine / 5120.0;return temperature;}double compensate_H(int32_t adc_H){ double var_h = t_fine - 76800.0;if (var_h == 0)return 0; var_h = (adc_H - (digH[3] * 64.0 + digH[4]/16384.0 * var_h)) *(digH[1] / 65536.0 * (1.0 + digH[5] / 67108864.0 * var_h * (1.0 + digH[2] / 67108864.0 * var_h))); var_h = var_h * (1.0 - digH[0] * var_h / 524288.0);if (var_h > 100.0) var_h = 100.0;else if (var_h < 0.0) var_h = 0.0;return var_h;} void get_calib_param(int handle){uint8_t calib[32];for(int i=0;i<24;i++) { calib[i] = lgI2cReadByteData(handle, 0x88 + i); } calib[24] = lgI2cReadByteData(handle, 0xA1);for(int i=25,o=0;i<32;i++,o++) { calib[i] = lgI2cReadByteData(handle, 0xE1 + o); } digT[0] = (calib[1] << 8) | calib[0]; digT[1] = (calib[3] << 8) | calib[2]; digT[2] = (calib[5] << 8) | calib[4]; digP[0] = (calib[7] << 8) | calib[6]; digP[1] = (calib[9] << 8) | calib[8]; digP[2] = (calib[11] << 8) | calib[10]; digP[3] = (calib[13] << 8) | calib[12]; digP[4] = (calib[15] << 8) | calib[14]; digP[5] = (calib[17] << 8) | calib[16]; digP[6] = (calib[19] << 8) | calib[18]; digP[7] = (calib[21] << 8) | calib[20]; digP[8] = (calib[23] << 8) | calib[22]; digH[0] = calib[24]; digH[1] = (calib[26] << 8) | calib[25]; digH[2] = calib[27]; digH[3] = (calib[28] << 4) | (0x0f & calib[29]); digH[4] = (calib[30] << 4) | ((calib[29] >> 4) & 0x0f); digH[5] = calib[31];for(int i=1;i<2;i++)if((digT[i] & 0x8000) != 0) digT[i] = (-digT[i] ^ 0xFFFF) + 1;for(int i=1;i<8;i++) if ((digP[i] & 0x8000) != 0) digP[i]=(-digP[i] ^ 0xFFFF) + 1 ; for(int i=0;i<6;i++) if ((digH[i] & 0x8000) != 0) digH[i] = (-digH[i] ^ 0xFFFF) + 1;}int main(int argc, char **argv){uint8_t data[8];double value[3];int handle = lgI2cOpen(I2C_DEV_NUM, BME280_ADDR, 0);lgI2cWriteByteData(handle, 0xF2, 0x01);lgI2cWriteByteData(handle, 0xF4, 0x27);lgI2cWriteByteData(handle, 0xF5, 0xA0);get_calib_param(handle);for(int i=0;i<8;i++) { data[i] = lgI2cReadByteData(handle, 0xF7 + i); } value[0] = (data[0] << 12) | (data[1] << 4) | (data[2] >> 4); value[1] = (data[3] << 12) | (data[4] << 4) | (data[5] >> 4); value[2] = (data[6] << 8) | data[7]; value[0] = compensate_P(value[0]); value[1] = compensate_T(value[1]); value[2] = compensate_H(value[2]);printf("pressure: %7.2f hPa\n", value[0]);printf("temperature: %7.2f C\n" , value[1]);printf("humidity: %7.2f %\n" , value[2]);lgI2cClose(handle);} ``` - 编译:**gcc -o envtest envtest.c -llgpio** - 运行:**./envtest** #输出内容包含采集的气压、温度和湿度信息 ## SPI测试 使用微雪 **2.23** 寸 **OLED** 显示器测试 **40-Pin** 中的 **SPI** 功能,对应设备节点 **/dev/spi10**,若节点未显示,您可以先使用本章介绍的 **qpi_config** 进行配置和使能。 连接示意图: ```{image} images/image_FkqrbiEe3ozcvDxu4NScVFTCnEf.webp :width: 590px :height: 413px ```
微雪环境传感器扩展板
```{image} images/image_KCzTbxTO1ohJKCxyAifcLZaKnVh.webp :width: 600px :height: 400px ``` Quectel Pi H1 40PIN引脚 测试步骤: - **wget**[** https://www.waveshare.net/w/upload/c/c5/2.23inch-OLED-HAT-Code.7z**]( ) #下载微雪提供的源码 - **7z x 2.23inch-OLED-HAT-Code.7z** #解压源码 - **cd 2.23inch-OLED-HAT-Code/Without\ scrolling/Raspberry\ Pi/SPI/c** #切换到源码目录 - 按照下列补丁的内容修改源码: ```c diff -r -u "2.23inch-OLED-HAT-Code/Without scrolling/Raspberry Pi/c/examples/main.c" quectelpi/c/examples/main.c --- "2.23inch-OLED-HAT-Code/Without scrolling/Raspberry Pi/c/examples/main.c" 2023-12-20 03:19:38.000000000 +0000+++ quectelpi/c/examples/main.c 2025-08-15 07:34:39.959415415 +0000 @@ -17,10 +17,13 @@ char value[10]={'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};time_t now;struct tm *timenow;-- if(DEV_ModuleInit() != 0) {- return -1;- }+ extern int GPIO_Handle;+ extern int SPI_Handle;+ GPIO_Handle = lgGpiochipOpen(4); if (GPIO_Handle < 0) { printf( "gpiochip4 Export Failed\n"); return -1; }+ lgGpioClaimOutput(GPIO_Handle, 0, 119 , LG_LOW); //enable OLED_DC mode+ lgGpioClaimOutput(GPIO_Handle, 0, OLED_RST, LG_LOW);+ lgGpioClaimOutput(GPIO_Handle, 0, OLED_DC , LG_LOW);+ SPI_Handle = lgSpiOpen(10, 0, 10000000, 0);SSD1305_begin();SSD1305_bitmap(7, 0, waveshare_ch,112,32);SSD1305_display(); Only in quectelpi/c/lib/Config: .DEV_Config.h.un~ diff -r -u "2.23inch-OLED-HAT-Code/Without scrolling/Raspberry Pi/c/lib/Config/DEV_Config.h" quectelpi/c/lib/Config/DEV_Config.h --- "2.23inch-OLED-HAT-Code/Without scrolling/Raspberry Pi/c/lib/Config/DEV_Config.h" 2023-12-20 03:23:11.000000000 +0000+++ quectelpi/c/lib/Config/DEV_Config.h 2025-08-15 07:32:05.844626084 +0000 @@ -41,8 +41,8 @@ //OLED Define#define OLED_CS 8 -#define OLED_RST 25 -#define OLED_DC 24 +#define OLED_RST 19+#define OLED_DC 33 ``` - 编译:**make** - 运行:**./main** - 运行效果如下图: ```{image} images/image_RESMbkPkNodR9wxVRMscv1IFnxd.webp :width: 814px :height: 545px ``` ## UART测试 **40-Pin** 的 **Pin8** 和 **Pin10** 默认配置为 **UART** 功能,对应设备节点 **/dev/ttyHS2**,若节点没出来可以先使用本章开头部分的 **qpi_config** 进行配置使能。 将电脑的 **USB** 转串口的 **RX** 接 **pin8**、**TX** 接 **pin10**。 连接示意图: ```{image} images/image_VdYRbD5BBoqWboxHhUpc4t42nBc.webp :width: 942px :height: 865px :align: center ``` ### 使用C代码控制 - 新建 **uart.c** 文件,内容如下: ```c #include #include #include int strip_head_and_tail(char *data, int data_len){int found_tail = 0;if (data_len > 0 && data[0] == '\r') {bcopy(data + 1, data, data_len-1); data_len--;}if (data_len > 0 && data[0] == '\n') {bcopy(data + 1, data, data_len-1); data_len--;}if (data_len > 0 && data[data_len - 1] == '\r') { data_len--; data[data_len] = 0; found_tail = 1;}if (data_len > 0 && data[data_len - 1] == '\n') { data_len--; data[data_len] = 0; found_tail = 1;}return found_tail;}int main(int argc, char **argv){int handle = lgSerialOpen("/dev/ttyHS2", 115200, 0);char data[512];int data_len = 0;for (;;) {int read_len = lgSerialRead(handle, data + data_len, sizeof(data) - data_len);if (read_len > 0) { data_len += read_len;}if (strip_head_and_tail(data, data_len)) {printf("received: %s\n", data);lgSerialWrite(handle, "Received.\r\n", 11);}lguSleep(100);}lgSerialClose(handle);} ``` - 编译:**gcc -o uart uart.c -llgpio** - 运行:**./uart** #此时 **USB** 转串口模块与 **PC** 连接,使用 **putty** 等支持串口通行的软件与该串口服务程序通行,**putty** 等客户端输入内容并以回车键结尾,服务端程序会打印用户输入的内容并返回“**Received**.”给客户端。 ### 使用Python脚本控制 - 创建服务端程序 **uart.py**,文件内容如下: ```python import serial import threading PORT = '/dev/ttyHS2' BAUDRATE = 115200 TIMEOUT = 1 ser = serial.Serial(PORT, BAUDRATE, timeout=TIMEOUT)def read_and_echo(ser):while True: data = ser.readline()if data:print(f"Received: {data.decode().strip()}") ser.write(“Received.\r\n”)def main():if ser.is_open:print(f"Serial port {PORT} is open. Echo service started.") thread = threading.Thread(target=read_and_echo, args=(ser,)) thread.daemon = True thread.start()try:while True:passexcept KeyboardInterrupt:print("Exiting program.")else:print(f"Failed to open serial port {PORT}.") ser.close()print(f"Serial port {PORT} is closed.")if __name__ == "__main__": main() ``` - 运行:**python test.py** #此时 **USB** 转串口模块与 **PC** 连接,使用 **putty** 等支持串口通行的软件与该串口服务程序通行,**putty** 等客户端输入内容并以回车键结尾,服务端程序会打印用户输入的内容并返回“**Received**.”给客户端。 ## PWM测试 **40-Pin** 的 **Pin33** 默认配置为 **PWM** 功能,这里选择微雪的 **4-Pin PWM** 协议的调速风扇做为测试设备。 ### 使用C代码控制 - 创建 **pwm.c** 文件,文件内容如下: ```c #include #include int main(int argc, char **argv){int h;int gpio = 78; float pwmFrequency = 1000;float pwmDutyCycle = 50; h = lgGpiochipOpen(4);if (h < 0) {printf("ERROR: %s (%d)\n", lguErrorText(h), h); return 1;} int e = lgGpioClaimOutput(h, 0, gpio, 0); if (e < 0) {printf("ERROR: %s (%d)\n", lguErrorText(e), e); return 1;} e = lgTxPwm(h, gpio, pwmFrequency, pwmDutyCycle, 0, 0); if (e < 0) {printf("ERROR: %s (%d)\n", lguErrorText(e), e); return 1;} lguSleep(5);lgGpioFree(h, gpio);lgGpiochipClose(h);return 0;} ``` - 编译:**gcc pwm.c -o pwm -llgpio** - 运行:**./pwm** #风扇会以中等转速运转,可以调整代码中的 **pwmDutyCycle** 值来调整风扇转速。 # 网络与通信 ## 蓝牙测试 **Quectel Pi H1** 智能主控板支持QCA1023 HCI UART蓝牙模块,可以连接常见蓝牙外设,以下流程演示与键鼠配对的方法。 ### 蓝牙模块启动 蓝牙模块为HCI UART连接主控,通过HCI H4协议进行通信。 首先,通过设备节点执行如下命令给外设供电。若为 **echo 0** 时,则给蓝牙外设下电。 ```shell echo 1 > /sys/devices/platform/rfkill/bt_en ``` 通过hciattach命令,通过串口初始化蓝牙模块。 ```shell hciattach /dev/ttyHS1 qca 3000000 flow ``` 通过hciconfig命令,查询并且启用HCI蓝牙设备。 ```shell hciconfig hci0 up ``` 通过 **hciconfig** 查询HCI设备状态。当状态为 **UP RUNNING** 时,说明HCI蓝牙设备已经启用。 ```shell root@qcm6490-idp:~# hciconfig hci0: Type: Primary Bus: UART BD Address: 00:00:00:00:5A:AD ACL MTU: 1024:7 SCO MTU: 60:8 UP RUNNING RX bytes:783665 acl:1106 sco:0 events:18678 errors:0 TX bytes:4072 acl:57 sco:0 commands:305 errors:0 ``` ### 连接蓝牙外设 执行 **bluetoothctl** 进入蓝牙配置工具。若命令提示符变成[bluetooth]#,表示已经进入蓝牙控制模式。 ```shell root@qcm6490-idp:~# bluetoothctl [bluetooth]# ``` 执行 **scan on** 开始扫描蓝牙设备,会显示周边蓝牙设备信息,此时需要打开蓝牙设备的配对模式,放在旁边。 ```shell [bluetooth]# scan on ``` 扫描到一定时间后,执行 **scan off**,停止扫描。 ```shell [bluetooth]# scan off ``` 执行 **devices**,列出扫描到的设备,找到你的蓝牙外设。此处以蓝牙鼠标为例。 ```shell [bluetooth]# devices Device C3:3E:68:5E:E7:1F MX Master 2S ``` 使用pair命令进行连接,地址为你的外设地址。 ```shell [bluetooth]# pair C3:3E:68:5E:E7:1F ``` 当输出CHG的日志时,说明配对成功。此时可以发现,该鼠标被注册到input设备下,这里为input5(请以实际注册地址为准)。 ```shell [CHG] Device C3:3E:68:5E:E7:1F Modalias: usb:v046DpB019d0006 [MX Master 2S]# [ 1157.381232][ T1737] input: MX Master 2S Keyboard as /devices/virtual/misc/uhid/0005:046D:B019.0001/input/input4[ 1157.392409][ T1737] input: MX Master 2S Mouse as /devices/virtual/misc/uhid/0005:046D:B019.0001/input/input5 ``` 将设备添加为trust并且连接(可选:如果设备自动连接则可跳过)。 ```shell [MX Master 2S]# trust C3:3E:68:5E:E7:1F Changing C3:3E:68:5E:E7:1F trust succeeded [MX Master 2S]# connect C3:3E:68:5E:E7:1F Attempting to connect to C3:3E:68:5E:E7:1F Connection successful ``` ### 验证外设 此时,我们可以用evtest工具来验证外设是否可用。输入 **evtest** 会显示可使用的event设备,这时选择鼠标对应的编号5。 ```shell root@qcm6490-idp:~# evtest No device specified, trying to scan all of /dev/input/event* Available devices: /dev/input/event0: pm8xxx_vib_ffmemless /dev/input/event1: gpio-keys /dev/input/event2: pmic_pwrkey /dev/input/event3: pmic_resin /dev/input/event4: MX Master 2S Keyboard /dev/input/event5: MX Master 2S Mouse Select the device event number [0-5]: ``` 当出现如下日志,则大功告成,可以通过移动鼠标和按键来测试是否有事件上报。 ```shell Input driver version is 1.0.1 Input device ID: bus 0x5 vendor 0x46d product 0xb019 version 0x6 Input device name: "MX Master 2S Mouse" Supported events: Event type 0 (EV_SYN) Event type 1 (EV_KEY) Event code 272 (BTN_LEFT) Event code 273 (BTN_RIGHT) Event code 274 (BTN_MIDDLE) Event code 275 (BTN_SIDE) Event code 276 (BTN_EXTRA) Event code 277 (BTN_FORWARD) Event code 278 (BTN_BACK) Event code 279 (BTN_TASK) Event code 280 (?) Event code 281 (?) Event code 282 (?) Event code 283 (?) Event code 284 (?) Event code 285 (?) Event code 286 (?) Event code 287 (?) Event type 2 (EV_REL) Event code 0 (REL_X) Event code 1 (REL_Y) Event code 6 (REL_HWHEEL) Event code 8 (REL_WHEEL) Event code 11 (REL_WHEEL_HI_RES) Event code 12 (REL_HWHEEL_HI_RES) Event type 4 (EV_MSC) Event code 4 (MSC_SCAN) Properties: Testing ... (interrupt to exit) Event: time 2618.445029, type 4 (EV_MSC), code 4 (MSC_SCAN), value 90001 Event: time 2618.445029, type 1 (EV_KEY), code 272 (BTN_LEFT), value 1 Event: time 2618.445029, -------------- SYN_REPORT ------------ Event: time 2618.610162, type 4 (EV_MSC), code 4 (MSC_SCAN), value 90001 Event: time 2618.610162, type 1 (EV_KEY), code 272 (BTN_LEFT), value 0 Event: time 2618.610162, -------------- SYN_REPORT ------------ ``` ## 有线网络(eth0) **Quectel Pi H1** 智能主控板支持 **1** 路自适应千兆以太网,以太网对网线的要求:仅支持直连网线,不支持交叉网线。 ### 网络配置 系统默认开启 **NetworkManager** 服务来管理网络。 #### 查看网络配置 使用 **ifconfig** 命令查看网络接口地址: ```{image} images/image_X7Fwb4OFGopWV1x4JEhcB4cLncf.webp :width: 548px :height: 293px ``` 使用 **route -n** 命令查看网络路由信息,里面包含默认网关地址信息: ```{image} images/image_XfyKbJuR2or7uSxpxrTcT5CcnTN.webp :width: 548px :height: 141px ``` 通过查看 **/etc/resolv.conf** 文件内容检查 **DNS** 服务器地址: ```{image} images/image_IKvPbfF48ohH0OxXsSHcnEzrn2e.webp :width: 548px :height: 55px ``` #### 自动获取网络配置 **【如果是通过网络远程连接到设备中修改网络,会有风丢失网络连接的风险,请确保有方法(如通过调试串口或显示器)查看修改后的网络配置】** 系统默认设置为自动获取网络配置。使用网线将设备接入局域网,设备会自动获取网络配置(前提条件:需要局域网中存在可用的 **DHCP** 服务)。 故障排除: - 查看连接信息:执行 *nmcli c*,观察输出的结果中 **DEVICE** 列是否包含 **eth0**,如果有,先删除再重建。 ```{image} images/image_WYqmbou2qonUdcxidkMcAIk1nwf.webp :width: 616px :height: 43px ``` - 删除旧的连接信息:执行 *nmcli c del 'Wired connection 1'* #这里的 '**Wired connection 1**'是从上一步中查询出的连接的 **NAME**。【删除后默认会自动创建一个 **NAME** 为 **eth0** 的连接,这个时候会自动获取网络配置】 ```{image} images/image_Cy3WbD6izoc3zNxYN7bcxGD2n8e.webp :width: 745px :height: 30px ``` - 新建连接并使能:执行 *nmcli c add type ethernet con-name eth0 ifname eth0* 来创建连接。这里指定了连接名为 **eth0**,使用的网络接口也是 **eth0**;再执行 *nmcli connection up eth0* 以使名为 **eth0** 的连接生效。【一般上一步删除旧连接后,会自动创建一个 **NAME** 为 **eth0** 的连接。这时会自动获取网络配置,如果某些情况下新的连接迟迟没有自动创建,可以执行该步骤来创建和使能新的连接】 ```{image} images/image_X5PubDP3cogNaPxl9bzciAUXntc.webp :width: 846px :height: 59px ``` #### 手动配置网络 **【如果是通过网络远程连接到设备中修改网络,会有风丢失网络连接的风险,请确保有方法(如通过调试串口或显示器)查看修改后的网络配置】** - 查看连接信息:执行 *nmcli c*,观察输出的结果中 **DEVICE** 列是否包含 **eth0**,若有,则需要记住其 **NAME** 值,后续步骤中需要用到。若无,则需要先创建一个 **eth0** 连接,执行 *nmcli c add type ethernet con-name 'Wired connection 1' ifname eth0*。 ```{image} images/image_QNBMbc4aeo1T5FxySgIcpNvWnze.webp :width: 616px :height: 43px ``` - 执行如下命令手动配置网络: ```shell nmcli c modify 'Wired connection 1' \ ipv4.addresses 192.168.1.100/24 \ ipv4.gateway 192.168.1.1 \ ipv4.dns 192.168.1.1 \ ipv4.method manual ``` - 修改完成后,执行 *nmcli c up 'Wired connection 1'* 使能连接【上述示例中的 **IP** 地址、网关地址和 **DNS** 地址根据实际需要修改】。 ### 测试网络 执行 **ping** 命令测试网络连接: - 执行 *ping 192.168.1.1*。如果 **ping** 通,则表示局域网网络连接正常【这里的 **IP** 地址需要修改为实际网络的网关地址】。 - 执行 *ping 114.114.114.114*。如果 **ping** 通,则表示外部网络连接正常。 - 执行 *ping baidu.com*。如果 **ping** 通,则表示外部网络连接正常且 **DNS** 解析功能正常。 ## Wi-Fi网络测试 使用 *nmcli* 快速连接Wi‑Fi: - 查看Wi‑Fi设备状态:*nmcli dev status* - 打开Wi‑Fi开关:*nmcli radio wifi on* - 扫描热点(指定Wi‑Fi设备):*nmcli dev wifi list ifname wlan0* - 连接热点:*nmcli dev wifi connect "Wi-Fi名称" password "Wi-Fi密码"* 执行连接命令后,若输出 *successfully activated* 即表示已成功联网。 ## PCIe 5G模块连接 **Quectel Pi H1** 智能主控板可以通过PCIe接口,通过转接板连接5G网卡,本文介绍使用PCIe转接板连接RM520N-GL PCIe网卡的使用方法。 ### PCIe模块配置 使用PCIe转接板,需要将5G模块设置成PCIe-EP模式,这样才能和Quectel Pi H1的PCIe接口通信。安装5G模块驱动后,通过转接板的USB口将Quectel Pi H1连接到5G模块,输入AT命令,将其切换到PCIe-EP模式。 1. 使用一根Type-C转USB线接入Windows电脑(此时您可能需要安装驱动,驱动文件由移远通信技术支持提供,请按照对应5G模块选择合适的驱动文件安装)。 ```{image} images/image_GQGbbvavToiufpxEnkkcOWwsnZd.webp :width: 1920px :height: 1437px ``` 2. 使用串口工具,打开模块AT端口。 可以在主机的设备管理器上查看端口,找到“Quectel USB AT Port(COM***)”端口。 ```shell AT+QCFG="data_interface",1,0 AT+QCFG="pcie/mode",0 AT+QCFG="usbnet",2 AT+CFUN=1,1 ``` 执行完命令,拔掉电脑端口的USB,重新给 **Quectel Pi H1** 上电之后,通过Shell口使用如下命令,判断5G模块是否被 **Quectel Pi H1** 正常识别并连接。 ```shell root@qcm6490-idp:~# lspci 0000:00:00.0 PCI bridge: Qualcomm Device 010b 0000:01:00.0 Ethernet controller: Device 1f0a:6801 (rev 01) 0001:00:00.0 PCI bridge: Qualcomm Device 010b 0001:01:00.0 Unassigned class [ff00]: Qualcomm Device 0308 root@qcm6490-idp:~# ls /dev/mhi* /dev/mhi_BHI /dev/mhi_DIAG /dev/mhi_DUN /dev/mhi_LOOPBACK /dev/mhi_QMI0 ``` 如果设备均被识别出来,则可以正常进行拨号操作。 ### 拨号上网 使用quectel-CM工具进行拨号上网,首先为5G模块连接天线,插入SIM卡,避免信号较差无法注网。 ```{image} images/image_UPINbpRWRoM5GJxwDDNc0Mahn1c.webp :width: 1920px :height: 1438px ``` 确认无误后,直接后台运行quectel-CM命令进行拨号。 ```shell root@qcm6490-idp:~# quectel-CM &[2] 1303 root@qcm6490-idp:~# [01-01_00:07:55:168] QConnectManager_Linux_V1.6.7[01-01_00:07:55:179] network interface '' or qmidev '' is not exist [01-01_00:07:55:179] netcard driver = pcie_mhi, driver version = V1.3.7 [01-01_00:07:55:179] qmap_mode = 1, qmap_version = 9, qmap_size = 15360, muxid = 0x81, qmap_netcard = rmnet_mhi0.1 [01-01_00:07:55:179] Modem works in QMI mode [01-01_00:07:55:193] /proc/1273/fd/7 -> /dev/mhi_QMI0 [01-01_00:07:55:193] /proc/1273/exe -> /usr/bin/quectel-CM [01-01_00:07:55:193] requestDeactivateDefaultPDP WdsConnectionIPv4Handle [01-01_00:07:55:424] ip link set dev rmnet_mhi0 down [01-01_00:07:55:431] ip addr flush dev rmnet_mhi0.1 [01-01_00:07:55:436] ip link set dev rmnet_mhi0.1 down [01-01_00:07:55:457] QmiWwanThread exit[01-01_00:07:55:459] qmi_main exit[01-01_00:07:57:196] cdc_wdm_fd = 7[01-01_00:07:57:208] Get clientWDS = 15[01-01_00:07:57:212] Get clientDMS = 1[01-01_00:07:57:215] Get clientNAS = 4[01-01_00:07:57:219] Get clientUIM = 3[01-01_00:07:57:224] Get clientWDA = 1[01-01_00:07:57:229] requestBaseBandVersion RM520NGLABR03A02M8G [01-01_00:07:57:232] qmap_settings.rx_urb_size = 15360[01-01_00:07:57:233] qmap_settings.ul_data_aggregation_max_datagrams = 11[01-01_00:07:57:233] qmap_settings.ul_data_aggregation_max_size = 8192[01-01_00:07:57:233] qmap_settings.dl_minimum_padding = 0[01-01_00:07:57:248] requestGetSIMStatus SIMStatus: SIM_READY [01-01_00:07:57:257] requestGetProfile[pdp:1 index:1] ctnet///0/IPV4V6 [01-01_00:07:57:261] requestRegistrationState2 MCC: 460, MNC: 11, PS: Attached, DataCap: 5G_SA [01-01_00:07:57:265] requestQueryDataCall IPv4ConnectionStatus: DISCONNECTED [01-01_00:07:57:265] ip link set dev rmnet_mhi0 down [01-01_00:07:57:272] ip addr flush dev rmnet_mhi0.1 [01-01_00:07:57:277] ip link set dev rmnet_mhi0.1 down [01-01_00:07:57:768] requestSetupDataCall WdsConnectionIPv4Handle: 0xe27891d0 [01-01_00:07:57:783] ip link set dev rmnet_mhi0 up [ 473.062494][ T1311] [I][mhi_netdev_open] Opened net dev interface [01-01_00:07:57:797] ip link set dev rmnet_mhi0.1 up [01-01_00:07:57:803] busybox udhcpc -f -n -q -t 5 -i rmnet_mhi0.1 udhcpc: started, v1.35.0 udhcpc: broadcasting discover udhcpc: broadcasting select for 192.168.134.67, server 192.168.134.68 udhcpc: lease of 192.168.134.67 obtained from 192.168.134.68, lease time 7200[01-01_00:07:57:883] /etc/udhcpc.d/50default: Adding DNS 8.8.8.8 [01-01_00:07:57:883] /etc/udhcpc.d/50default: Adding DNS 8.8.4.4 ``` 当最后两行udhcpc获取到IP地址后,说明已经可以正常获取到基站分配的IP,即表示可以上网。 使用ifconfig和ping命令验证网络: ```shell root@qcm6490-idp:~# ifconfig eth0 Link encap:Ethernet HWaddr 00:55:7B:B5:7D:F7 UP BROADCAST MULTICAST MTU:1500 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) Interrupt:166 lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:65536 Metric:1 RX packets:50 errors:0 dropped:0 overruns:0 frame:0 TX packets:50 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:4632 (4.5 KiB) TX bytes:4632 (4.5 KiB) p2p0 Link encap:Ethernet HWaddr 02:03:7F:D6:00:01 UP BROADCAST MULTICAST MTU:1500 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:3000 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) rmnet_mhi0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 inet6 addr: fe80::6921:e40e:336d:a80e/64 Scope:Link UP RUNNING NOARP MTU:1500 Metric:1 RX packets:14 errors:0 dropped:0 overruns:0 frame:0 TX packets:23 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:4464 (4.3 KiB) TX bytes:5204 (5.0 KiB) rmnet_mhi0.1 Link encap:Ethernet HWaddr 02:50:F4:00:00:01 inet addr:192.168.134.67 Mask:255.255.255.248 inet6 addr: fe80::50:f4ff:fe00:1/64 Scope:Link UP RUNNING NOARP MTU:1500 Metric:1 RX packets:14 errors:0 dropped:0 overruns:0 frame:0 TX packets:23 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:4330 (4.2 KiB) TX bytes:5334 (5.2 KiB) wlan0 Link encap:Ethernet HWaddr 00:03:7F:50:00:01 UP BROADCAST MULTICAST MTU:1500 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:3000 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) root@qcm6490-idp:~# ping 8.8.8.8 PING 8.8.8.8 (8.8.8.8): 56 data bytes 64 bytes from 8.8.8.8: seq=0 ttl=113 time=5006.075 ms 64 bytes from 8.8.8.8: seq=5 ttl=113 time=485.806 ms 64 bytes from 8.8.8.8: seq=6 ttl=113 time=190.026 ms 64 bytes from 8.8.8.8: seq=13 ttl=113 time=628.962 ms 64 bytes from 8.8.8.8: seq=14 ttl=113 time=542.605 ms 64 bytes from 8.8.8.8: seq=15 ttl=113 time=585.632 ms 64 bytes from 8.8.8.8: seq=16 ttl=113 time=796.018 ms 64 bytes from 8.8.8.8: seq=17 ttl=113 time=95.139 ms 64 bytes from 8.8.8.8: seq=18 ttl=113 time=837.369 ms 64 bytes from 8.8.8.8: seq=19 ttl=113 time=41.186 ms ``` # 图形与显示 ## GPU性能测试 ### 背景 在当今数字化时代,图形处理能力已成为衡量开发板性能的关键指标之一,**Quectel Pi H1** 智能主控板,凭借其内置的高通 **Adreno 642L/643 GPU**,在图形处理领域展现出了令人瞩目的实力,想象一下,在智慧交通场景中,**Quectel Pi H1** 智能主控板能够凭借其强大的 **GPU** 性能,快速且精准地识别并标注车辆、车牌以及行人等目标物体,为交通管理提供实时且准确的数据支持。又或者在智能安全领域,面对复杂多变的监控画面,它能借助 **GPU** 卓越的运算能力,迅速完成图像识别与分析,及时发现潜在风险。这一切高效且精准的图形处理背后,正是 **Quectel Pi H1** **GPU** 性能的生动体现。它不仅能轻松应对日常的多媒体处理任务,更在对图形运算要求极高的复杂应用场景中,表现得游刃有余。以下通过 **glmark2** 基准测试工具,用于评估 **Quectel Pi H1** 的图形渲染性能。 **glmark2** 是一款开源的 **OpenGL ES** 和 **EGL** 基准测试工具,主要用于评估设备的图形渲染性能。它通过运行一系列标准化测试场景(如纹理填充、光照计算、像素处理等),量化 **GPU** 的帧率(**FPS**)、延迟(**FrameTime**)和稳定性,适用于嵌入式设备、手机、开发板等平台的图形性能分析和调优。 ### 测试环境 **glmark2** 默认已集成到系统镜像并安装。进入设备终端可直接测试性能。 - 准备显示器,并连接显示器到 **Quectel Pi H1** 上。 ### 运行命令 - 在设备终端运行以下命令以确保结果显示在连接的显示器上: ```bash export XDG_RUNTIME_DIR=/dev/socket/weston && export WAYLAND_DISPLAY=wayland-1 ``` - 运行 **glmark2** 命令以测试图形渲染性能: ```bash glmark2-es2-wayland ``` ### 测试结果 ```plaintext QUALCOMM build : a4d6ce04e1, I363e8f8d61 Build Config : G ESX_C_COMPILER_OPT 4.4.0 AArch64 Driver Path : /usr/lib/libGLESv2_adreno.so Driver Version : 0808.0 Process Name : glmark2-es2-wayland GBM_INFO::msmgbm_mapper(262)::gbm mapper instantiated gbm_create_device(224): Info: backend name is: msm_drm PFP: 0x016dc112, ME: 0x00000000 I/Adreno-UNKNOWN (1382,1382): : Reading chip ID through GSL Pre-rotation disabled !!! EGL updater thread started ======================================================= glmark2 2021.12 ======================================================= OpenGL Information GL_VENDOR: Qualcomm GL_RENDERER: Adreno (TM) 643 GL_VERSION: OpenGL ES 3.2 ======================================================= [build] use-vbo=false: FPS: 516 FrameTime: 1.938 ms [build] use-vbo=true: FPS: 679 FrameTime: 1.473 ms [texture] texture-filter=nearest: FPS: 748 FrameTime: 1.337 ms [texture] texture-filter=linear: FPS: 722 FrameTime: 1.385 ms [texture] texture-filter=mipmap: FPS: 231 FrameTime: 4.329 ms [shading] shading=gouraud: FPS: 220 FrameTime: 4.545 ms [shading] shading=blinn-phong-inf: FPS: 679 FrameTime: 1.473 ms [shading] shading=phong: FPS: 221 FrameTime: 4.525 ms [shading] shading=cel: FPS: 688 FrameTime: 1.453 ms [bump] bump-render=high-poly: FPS: 693 FrameTime: 1.443 ms [bump] bump-render=normals:[ 606.705365][ T943] smcinvoke: process_accept_req: Setting pid:943, server id : 23 state to defunct [ 606.714752][ T944] smcinvoke: process_accept_req: Setting pid:944, server id : 23 state to defunct [ 606.724315][ T945] smcinvoke: process_accept_req: Setting pid:945, server id : 23 state to defunct [ 606.734878][ T946] smcinvoke: process_accept_req: Setting pid:946, server id : 23 state to defunct [ 606.751381][ T943] smcinvoke: process_tzcb_req: server is defunct, state= 1 tzhandle = -2147483625 [ 606.760794][ T943] smcinvoke: process_tzcb_req: server invalid, res: -90 FPS: 714 FrameTime: 1.401 ms [bump] bump-render=height: FPS: 674 FrameTime: 1.484 ms [effect2d] kernel=0,1,0;1,-4,1;0,1,0;: FPS: 373 FrameTime: 2.681 ms [effect2d] kernel=1,1,1,1,1;1,1,1,1,1;1,1,1,1,1;: FPS: 251 FrameTime: 3.984 ms [pulsar] light=false:quads=5:texture=false: FPS: 213 FrameTime: 4.695 ms [desktop] blur-radius=5:effect=blur:passes=1:separable=true:windows=4: FPS: 559 FrameTime: 1.789 ms [desktop] effect=shadow:windows=4: FPS: 466 FrameTime: 2.146 ms Error: Requested MapBuffer VBO update method but GL_OES_mapbuffer is not supported! [buffer] columns=200:interleave=false:update-dispersion=0.9:update-fraction=0.5:update-method=map: Unsupported [buffer] columns=200:interleave=false:update-dispersion=0.9:update-fraction=0.5:update-method=subdata: FPS: 238 FrameTime: 4.202 ms Error: Requested MapBuffer VBO update method but GL_OES_mapbuffer is not supported! [buffer] columns=200:interleave=true:update-dispersion=0.9:update-fraction=0.5:update-method=map: Unsupported [ideas] speed=duration: FPS: 578 FrameTime: 1.730 ms [jellyfish] : FPS: 642 FrameTime: 1.558 ms [terrain] : FPS: 74 FrameTime: 13.514 ms [shadow] : FPS: 527 FrameTime: 1.898 ms [refract] : FPS: 418 FrameTime: 2.392 ms [conditionals] fragment-steps=0:vertex-steps=0: FPS: 679 FrameTime: 1.473 ms [conditionals] fragment-steps=5:vertex-steps=0: FPS: 686 FrameTime: 1.458 ms [conditionals] fragment-steps=0:vertex-steps=5: FPS: 230 FrameTime: 4.348 ms [function] fragment-complexity=low:fragment-steps=5: FPS: 680 FrameTime: 1.471 ms [function] fragment-complexity=medium:fragment-steps=5: FPS: 693 FrameTime: 1.443 ms [loop] fragment-loop=false:fragment-steps=5:vertex-steps=5: FPS: 691 FrameTime: 1.447 ms [loop] fragment-steps=5:fragment-uniform=false:vertex-steps=5: FPS: 240 FrameTime: 4.167 ms [loop] fragment-steps=5:fragment-uniform=true:vertex-steps=5: FPS: 685 FrameTime: 1.460 ms ======================================================= glmark2 Score: 506 ======================================================= EGL updater thread exited ``` ### 性能分析 glmark2基准测试报告显示的Quectel Pi H1的OpenGL ES图形性能,最终得分为506,总体表现不错。主要性能表现如下: VBO(顶点缓冲对象)优化 - use-vbo=false → 516 FPS - use-vbo=true → 679 FPS(提升31.6%) 结论:启用VBO能显著提升渲染效率,减少CPU-GPU数据传输开销。 纹理过滤模式 - nearest(最近邻)→ 748 FPS(最快) - linear(线性)→ 722 FPS(轻微性能损失) - mipmap(多级渐远)→ 231 FPS(性能下降69%) 结论:mipmap因额外计算开销导致帧率大幅下降,适合高质量纹理但代价高。 着色模型(Shading) - blinn-phong-inf(优化版布林-冯模型)→ 679 FPS - cel(卡通渲染)→ 688 FPS - phong/gouraud(传统光照模型)→ 220 FPS(性能极低) 结论:现代着色器(如blinn-phong-inf)比传统模型(如phong)更高效。 ## HDMI屏测试 **Quectel Pi H1** 智能主控板支持 **HDMI** 接口显示屏。 ### HDMI屏连接 按照下图进行连接: ```{image} images/image_Qn6ibd7C4oviMvx5ADocj3cXnie.webp :width: 1496px :height: 1120px ```
11.6寸HDMI显示屏
```{image} images/image_S2qEbXjuPoGQPcxcoXlcn06inje.webp :width: 1710px :height: 1279px ```
连接上HDMI显示屏后的Quectel Pi H1
### HDMI屏显示Weston桌面 连接上 **HDMI** 显示器并上电开机后,启动显示服务:**systemctl start init_display**,**HDMI** 屏会显示 **Weston** 桌面。 显示效果如下图: ```{image} images/image_DIBfbqt6qo4UefxZwXkc7Stanch.webp :width: 1118px :height: 655px ``` ### 利用HDMI屏播放视频 执行视频回放命令: ```shell mount -o rw,remount / export XDG_RUNTIME_DIR=/dev/socket/weston export WAYLAND_DISPLAY=wayland-1 gst-launch-1.0 -e filesrc location=/root/quectel.mp4 ! qtdemux ! \ queue ! h264parse ! v4l2h264dec capture-io-mode=5 output-io-mode=5 ! \ waylandsink enable-last-sample=false fullscreen=true #其中location后的参数根据实际视频路径进行修改 ``` 命令说明: - *gst-launch-1.0*:这是 **GStreamer** 的命令行工具,用于启动一个 **GStreamer** 管道(**pipeline**)。**-e** 参数表示在管道结束时退出,而不是继续运行。 - *filesrc location=/root/quectel.mp4*:**filesrc** 用于从文件中读取数据, **location=/root/quectel.mp4** 指定要读取的文件路径。 - *! qtdemux*:**!** 是一个连接符号,用于将前一个元素的输出连接到后一个元素的输入,**qtdemux** 用于解复用 **MP4** 文件。**MP4** 文件通常包含视频流和音频流,**qtdemux** 的作用是将这些流分离出来,以便后续处理。 - *! queue*:**queue** 是一个缓冲队列元素,用于在管道中缓冲数据。它可以缓解数据处理速度不一致的问题,例如,当解码器处理速度较慢时,**queue** 可以暂存数据,避免数据丢失。 - *! h264parse*:**h264parse** 用于解析 **H.264** 视频流。它会将 **H.264** 视频流中的数据重新组织成适合解码器处理的格式。 - *! v4l2h264dec capture-io-mode=5 output-io-mode=5*:**v4l2h264dec** 用于解码 **H.264** 视频流,**capture-io-mode=5**:设置捕获输入模式为 **5**,这通常与硬件加速有关,具体含义取决于硬件和驱动程序;**output-io-mode=5** 设置输出模式为 **5**,同样与硬件加速相关。 - *! waylandsink enable-last-sample=false fullscreen=true*:**waylandsink** 用于将解码后的视频输出到 **Wayland** 显示服务器上,**enable-last-sample=false** 禁用“最后样本”功能,这通常是用于优化性能或避免某些问题;**fullscreen=true** 将视频以全屏模式显示。 视频回放效果如下图: ```{image} images/image_QudkbnDcXoJQ1zxNIHccgiC0nfd.webp :width: 1119px :height: 656px ``` ## MIPI屏测试 **Quectel Pi H1** 智能主控板支持 **MIPI** 接口显示屏,下面选取微雪的一款 **8** 寸 **DSI** 接口 **ISP** 电容触摸屏为例进行测试。 ### MIPI屏连接 按照下图进行连接: 注:此屏幕共有4处接口可供电,任选一处即可,示例选择“1”处供电。 1. 即 **type-C** 接口 2. **I2C** 通讯与供电接口 3. **5V** 输入输出接口 4. **I2C** 通讯与供电接口,需将螺丝孔对准 **Quectel Pi H1** 智能主控板拧紧,让顶针与 **40-Pin** 连接牢固 ```{image} images/image_SS9tbVtnZoTEKrxgmfrcHVx9nmf.webp :width: 1324px :height: 941px ```
微雪8寸MIPI显示屏背面
```{image} images/image_CT02bFQ0foX9lUxhpbncnLYLnFd.webp :width: 3264px :height: 2324px ```
连接上MIPI显示屏后的Quectel Pi H1
### MIPI屏显示Weston桌面 连接上 **MIPI** 显示器并上电开机后,启动显示服务:**systemctl start init_display**,**MIPI** 屏会显示 **Weston** 桌面。 显示效果如下图: ```{image} images/image_JDppbCEYKoYN6Dxo4M4cJorfnR1.webp :width: 1118px :height: 655px ``` ### 利用MIPI屏播放视频 执行视频回放命令: ```shell mount -o rw,remount / export XDG_RUNTIME_DIR=/dev/socket/weston export WAYLAND_DISPLAY=wayland-1 gst-launch-1.0 -e filesrc location=/root/quectel.mp4 ! qtdemux ! \ queue ! h264parse ! v4l2h264dec capture-io-mode=5 output-io-mode=5 ! \ waylandsink enable-last-sample=false fullscreen=true #其中location后的参数根据实际视频路径进行修改 ``` 命令说明: - *gst-launch-1.0*:这是 **GStreamer** 的命令行工具,用于启动一个 **GStreamer** 管道(**pipeline**)。**-e** 参数表示在管道结束时退出,而不是继续运行。 - *filesrc location=/root/quectel.mp4*:**filesrc** 用于从文件中读取数据, **location=/root/quectel.mp4** 指定要读取的文件路径。 - *! qtdemux*:**!** 是一个连接符号,用于将前一个元素的输出连接到后一个元素的输入,**qtdemux** 用于解复用 **MP4** 文件。**MP4** 文件通常包含视频流和音频流,**qtdemux** 的作用是将这些流分离出来,以便后续处理。 - *! queue*:**queue** 是一个缓冲队列元素,用于在管道中缓冲数据。它可以缓解数据处理速度不一致的问题,例如,当解码器处理速度较慢时,**queue** 可以暂存数据,避免数据丢失。 - *! h264parse*:**h264parse** 用于解析 **H.264** 视频流。它会将 **H.264** 视频流中的数据重新组织成适合解码器处理的格式。 - *! v4l2h264dec capture-io-mode=5 output-io-mode=5*:**v4l2h264dec** 用于解码 **H.264** 视频流,**capture-io-mode=5**:设置捕获输入模式为 **5**,这通常与硬件加速有关,具体含义取决于硬件和驱动程序;**output-io-mode=5** 设置输出模式为 **5**,同样与硬件加速相关。 - *! waylandsink enable-last-sample=false fullscreen=true*:**waylandsink** 用于将解码后的视频输出到 **Wayland** 显示服务器上,**enable-last-sample=false** 禁用“最后样本”功能,这通常是用于优化性能或避免某些问题;**fullscreen=true** 将视频以全屏模式显示。 视频回放效果如下图: ```{image} images/image_RNmdbSptsoSJFlxxtducWE6Xnie.webp :width: 1119px :height: 656px ``` ## DP屏测试 **Quectel Pi H1** 智能主控板支持通过 **Type-C** 转 **DP** 接口的方法接显示屏。 ### DP屏连接 按照下图进行连接: ```{image} images/image_N2HGbnj0WoXMkkxAfQPc50TMngc.webp :width: 915px :height: 694px ``` ### DP屏显示Weston桌面 连接上 **DP** 显示器并上电开机后,启动显示服务:**systemctl start init_display**,**DP** 屏会显示 **Weston** 桌面。 显示效果如下图: ```{image} images/image_MGZybUJ8WoHHwkxerF5co044nyh.webp :width: 1113px :height: 891px ``` ### 利用DP屏播放视频 执行视频回放命令: ```shell mount -o rw,remount / export XDG_RUNTIME_DIR=/dev/socket/weston export WAYLAND_DISPLAY=wayland-1 gst-launch-1.0 -e filesrc location=/root/quectel.mp4 ! qtdemux ! \ queue ! h264parse ! v4l2h264dec capture-io-mode=5 output-io-mode=5 ! \ waylandsink enable-last-sample=false fullscreen=true #其中location后的参数根据实际视频路径进行修改 ``` 命令说明: - *gst-launch-1.0*:这是 **GStreamer** 的命令行工具,用于启动一个 **GStreamer** 管道(**pipeline**)。**-e** 参数表示在管道结束时退出,而不是继续运行。 - *filesrc location=/root/quectel.mp4*:**filesrc** 用于从文件中读取数据, **location=/root/quectel.mp4** 指定要读取的文件路径。 - *! qtdemux*:**!** 是一个连接符号,用于将前一个元素的输出连接到后一个元素的输入,**qtdemux** 用于解复用 **MP4** 文件。**MP4** 文件通常包含视频流和音频流,**qtdemux** 的作用是将这些流分离出来,以便后续处理。 - *! queue*:**queue** 是一个缓冲队列元素,用于在管道中缓冲数据。它可以缓解数据处理速度不一致的问题,例如,当解码器处理速度较慢时,**queue** 可以暂存数据,避免数据丢失。 - *! h264parse*:**h264parse** 用于解析 **H.264** 视频流。它会将 **H.264** 视频流中的数据重新组织成适合解码器处理的格式。 - *! v4l2h264dec capture-io-mode=5 output-io-mode=5*:**v4l2h264dec** 用于解码 **H.264** 视频流,**capture-io-mode=5**:设置捕获输入模式为 **5**,这通常与硬件加速有关,具体含义取决于硬件和驱动程序;**output-io-mode=5** 设置输出模式为 **5**,同样与硬件加速相关。 - *! waylandsink enable-last-sample=false fullscreen=true*:**waylandsink** 用于将解码后的视频输出到 **Wayland** 显示服务器上,**enable-last-sample=false** 禁用"最后样本"功能,这通常是用于优化性能或避免某些问题;**fullscreen=true** 将视频以全屏模式显示。 视频回放效果如下图: ```{image} images/image_IWQKbKLKaoYmuPxWUK9ctXuXnld.webp :width: 1114px :height: 892px ``` # 摄像头方案 ## MIPI摄像头(IMX219)测试 **Quectel Pi H1** 智能主控板支持 **MIPI** 接口摄像头,下面选取微雪的一款 **imx219** **CSI** 接口 **CMOS** 摄像头为例进行测试。 ### 摄像头连接 按照下图进行连接,连接时向上拉开连接器的黑色锁扣部分,将 **FPC** 排线插入第一个 **CSI** 卡槽,注意金属接触面朝向板内金属接触面,按下锁扣,确认 **FPC** 排线稳定没有松动。 ```{image} images/image_GbnZbQ7bCotk1OxpLFdcyJBbn2c.webp :width: 3264px :height: 2412px ``` ### 前提条件 在 **SSH** 终端中运行以下命令: ```shell mount -o rw,remount / export XDG_RUNTIME_DIR=/dev/socket/weston export WAYLAND_DISPLAY=wayland-1 ``` ### 单摄像头流启动 1. 在 **device** 终端中运行如下命令。 ```shell gst-launch-1.0 -e qtiqmmfsrc name=camsrc ! 'video/x-raw(memory:GBM),format=NV12,width=1280,height=720,framerate=30/1' ! fakesink ``` 2. 此示例说明如何使用 **720p@30 FPS** 配置启动摄像头。该命令使用 **fakesink**(虚拟接收器)作为输出,**fakesink** 会接收来自摄像头传感器的帧数据但不做任何处理,直接丢弃,因此不会在设备上保存任何内容。此命令仅用于测试摄像头是否正常工作。如果 **gst pipeline** 状态更改为 **“PLAYING”**,如下所示,则表示摄像头正在运行。 ```shell gbm_create_device(187): Info: backend name is: msm_drm Setting pipeline to PAUSED ... Pipeline is live and does not need PREROLL ... Setting pipeline to PLAYING ... New clock: GstSystemClock ``` 3. 如果想实时显示摄像头捕捉的画面,需提前连接好 **HDMI** 屏幕,并执行以下命令: ```shell gst-launch-1.0 -e qtiqmmfsrc name=camsrc camera=0 ! 'video/x-raw(memory:GBM),format=NV12,width=1280,height=720,framerate=30/1' ! waylandsink ``` - **camera=0** 表示使用第一个 **CSI** 接口摄像头,**camera=1** 表示使用第二个 **CSI** 接口摄像头。 - 如果想全屏显示,请在命令后面加上 *fullscreen=true* - 如果要停止摄像头流,请按下 *CTRL+C* ### 预览+视频录制 1. 在 **device** 终端中运行以下命令: ```shell gst-launch-1.0 -e qtiqmmfsrc name=camsrc camera=0 video_1::type=preview ! 'video/x-raw,format=NV12,width=1280,height=720,framerate=30/1',compression=ubwc,interlace-mode=progressive,colorimetry=bt601 ! tee name=t ! queue ! waylandsink fullscreen=true t. ! queue ! v4l2h264enc capture-io-mode=5 output-io-mode=5 extra-controls="controls,video_bitrate=6000000,video_bitrate_mode=0;" ! queue ! h264parse ! mp4mux ! filesink location=/opt/mux_avc.mp4 ``` 2. 此命令以 **720p 30 FPS** 配置启动相机,并在 **h264** 视频编码后将其另存为视频文件。如果 **gst** 管道状态更改为 **“PLAYING”**,则表示摄像头正在运行。 3. 如果要停止摄像头录制,请按下 *CTRL+C*。 4. **MP4** 文件保存在 **/opt/** 目录。 命令说明: - **!** 是一个连接符号,用于将前一个元素的输出连接到后一个元素的输入。 - *gst-launch-1.0*:这是 **GStreamer** 的命令行工具,用于启动一个 **GStreamer** 管道(**pipeline**)。**-e** 参数表示在管道结束时退出,而不是继续运行。 - *qtiqmmfsrc name=camsrc camera=0*:高通平台专用的摄像头源插件,从设备 **camera=0**(主摄像头)采集视频。 - *video_1::type=preview*:这是 **qtiqmmfsrc** 元素的属性配置,针对 **video_1** 流(不同摄像头可能输出多路流,比如预览流、抓拍流等),设置其类型为 **preview**(预览流),表示后续处理的是用于实时预览场景的视频流,一般帧率、分辨率等参数会适配预览需求。 - *video/x-raw,format=NV12,width=1280,height=720,framerate=30/1*:**video/x-raw**(原始视频),**NV12**(**YUV 4:2:0**,单平面格式,常见于视频编码),分辨率 **1280×720(720p)**,帧率 **30fps**。 - *compression=ubwc,interlace-mode=progressive,colorimetry=bt601*:启用高通的 **UBWC(Ultra Bandwidth Compression)** 技术,通过硬件压缩减少内存带宽需求,逐行扫描(非隔行),色彩空间为 **ITU-R BT.601**(适用于标清视频)。 - *tee name=t*:分流器(**tee**)元素,作用是将一路输入数据复制成多路输出,方便对同一视频流进行多种不同处理(这里一路用于预览显示,一路用于编码存储)。**name=t** 给这个 **tee** 元素命名为 **t**,后续其他分支通过名字引用它来获取视频流。 - *queue ! waylandsink fullscreen=true*:**queue**:队列元素,用于在 **pipeline** 中创建一个缓冲队列,起到解耦上下游元素、异步处理的作用。可以缓解上下游处理速度不一致的问题,避免因一方处理慢导致另一方阻塞或丢帧。 **waylandsink**:输出 **sink** 元素,用于在 **Wayland** 显示服务器环境下,将视频画面渲染显示到屏幕上。 **fullscreen=true**:设置 **waylandsink** 以全屏模式显示视频画面。 - *t. ! queue*:**t.**:通过.语法引用之前命名为 **t** 的 **tee** 元素,获取视频流进行后续处理。 **queue**:再次使用队列元素,缓冲数据,保证编码等环节的流畅性。 - *v4l2h264enc capture-io-mode=5 output-io-mode=5 extra-controls="controls,video_bitrate=6000000 video_bitrate_mode=0;"*:使用 **DMABUF**(直接内存访问缓冲区)进行输入,优化数据传输效率,同样使用 **DMABUF** 输出编码后数据,目标比特率为 **6 Mbps**,使用 **CBR**(固定比特率)模式,适合网络流媒体或需要稳定带宽的场景。 - *queue ! h264parse ! mp4mux ! filesink location=/opt/mux_avc.mp4*:**queue**:又一个队列元素,继续缓冲编码后的数据,协调后续处理速度。解析 **H.264** 流,添加必要的 **NAL** 单元头部,使其符合 **MP4** 封装要求,将 **H.264** 视频流封装为 **MP4** 格式,将数据写入文件 **/opt/mux_avc.mp4**。 ### 预览+拍照 1. 在 **device** 终端中运行以下命令: ```shell gst-pipeline-app -e qtiqmmfsrc name=camsrc camera=0 ! 'video/x-raw(memory:GBM),format=NV12,width=1280,height=720,framerate=30/1' ! waylandsink camsrc.image_1 ! "image/jpeg,width=1280,height=720,framerate=30/1" ! multifilesink location=/opt/frame%d.jpg async=false sync=true ``` 2. 按 *Enter* 键。此命令将打印以下菜单并等待用户输入。 ```shell ##################################### MENU #####################################============================== Pipeline Controls==============================(0) NULL: Set the pipeline into NULL state (1) READY: Set the pipeline into READY state (2) PAUSED: Set the pipeline into PAUSED state (3) PLAYING: Set the pipeline into PLAYING state ==================================== Other====================================(p) Plugin Mode: Choose a plugin which to control (q) Quit : Exit the application Choose an option: ``` 3. 使用以下菜单步骤在预览时拍摄快照。 ```shell (1) ready -> (3) Playing -> (Enter)-> (p)Plugin Mode : Select (5)camerasrc ->(36) capture-image -> (1): still – Snapshot ->(1) Snapshot count ('guint' value for arg1) ``` 4. 要停止相机,请按 *Enter*,按 *b*(返回),然后按 *q*(退出)。拍摄的快照图像保存在 **/opt/** 中。通过在主机 **PC** 上运行以下 *scp* 命令,可以从设备中提取录制的内容: ```shell scp -r root@[ip-addr]:/opt/ . ``` - 生成文件如下图所示: ```{image} images/image_ISAGbxkzOoiQiKxWA26cjH8dnIb.webp :width: 369px :height: 34px ``` ## MIPI摄像头(IMX477)测试 **Quectel Pi H1** 智能主控板支持 **MIPI** 接口摄像头,下面选取微雪的一款 **imx477** **CSI** 接口 **CMOS** 摄像头为例进行测试。 ### 摄像头连接 按照下图进行连接,连接时向上拉开连接器的黑色锁扣部分,将 **FPC** 排线插入第二个 **CSI** 卡槽,注意金属接触面朝向板内金属接触面,按下锁扣,确认 **FPC** 排线稳定没有松动。 ```{image} images/image_CoygbwE0Jopp5Zxh489c0B7knnc.webp :width: 3264px :height: 2396px ``` ### 前提条件 在 **SSH** 终端中运行以下命令: ```shell mount -o rw,remount / export XDG_RUNTIME_DIR=/dev/socket/weston export WAYLAND_DISPLAY=wayland-1 ``` ### 单摄像头流启动 1. 在 **device** 终端中运行以下命令。 ```shell gst-launch-1.0 -e qtiqmmfsrc name=camsrc camera=1 ! 'video/x-raw(memory:GBM),format=NV12,width=1280,height=720,framerate=30/1' ! fakesink ``` 2. 此示例说明如何使用 **720p@30 FPS** 配置启动摄像头。该命令使用 **fakesink**(虚拟接收器)作为输出,**fakesink** 会接收来自摄像头传感器的帧数据但不做任何处理,直接丢弃,因此不会在设备上保存任何内容。此命令仅用于测试摄像头是否正常工作。如果 **gst pipeline** 状态更改为 **“PLAYING”**,如下所示,则表示摄像头正在运行。 ```shell gbm_create_device(187): Info: backend name is: msm_drm Setting pipeline to PAUSED ... Pipeline is live and does not need PREROLL ... Setting pipeline to PLAYING ... New clock: GstSystemClock ``` 3. 如果想实时显示摄像头捕捉的画面,需提前连接好 **HDMI** 屏幕,并执行以下命令: ```shell gst-launch-1.0 -e qtiqmmfsrc name=camsrc camera=1 ! 'video/x-raw(memory:GBM),format=NV12,width=1280,height=720,framerate=30/1' ! waylandsink ``` - **camera=0** 表示使用第一个 **CSI** 接口摄像头,**camera=1** 表示使用第二个 **CSI** 接口摄像头。 - 如果想全屏显示,请在命令后面加上 *fullscreen=true*。 - 如果要停止摄像头流,请按下 *CTRL+C*。 ### 预览+视频录制 1. 在 **device** 终端中运行以下命令: ```shell gst-launch-1.0 -e qtiqmmfsrc name=camsrc camera=1 video_1::type=preview ! 'video/x-raw,format=NV12,width=1280,height=720,framerate=30/1',compression=ubwc,interlace-mode=progressive,colorimetry=bt601 ! tee name=t ! queue ! waylandsink fullscreen=true t. ! queue ! v4l2h264enc capture-io-mode=5 output-io-mode=5 extra-controls="controls,video_bitrate=6000000,video_bitrate_mode=0;" ! queue ! h264parse ! mp4mux ! filesink location=/opt/mux_avc.mp4 ``` 2. 此命令以 **720p 30 FPS** 配置启动相机,并在 **h264** 视频编码后将其另存为视频文件。如果 **gst** 管道状态更改为 **“PLAYING”**,则表示摄像头正在运行。 3. 如果要停止摄像头录制,请按下 *CTRL+C*。 4. **MP4** 文件保存在 **/opt/** 目录。 命令说明: - **!** 是一个连接符号,用于将前一个元素的输出连接到后一个元素的输入 - *gst-launch-1.0*:这是 **GStreamer** 的命令行工具,用于启动一个 **GStreamer** 管道(**pipeline**)。**-e** 参数表示在管道结束时退出,而不是继续运行。 - *qtiqmmfsrc name=camsrc camera=1*:高通平台专用的摄像头源插件,从设备 **camera=1**(副摄像头)采集视频。 - *video_1::type=preview*:这是 **qtiqmmfsrc** 元素的属性配置,针对 **video_1** 流(不同摄像头可能输出多路流,比如预览流、抓拍流等),设置其类型为 **preview**(预览流),表示后续处理的是用于实时预览场景的视频流,一般帧率、分辨率等参数会适配预览需求。 - *video/x-raw,format=NV12,width=1280,height=720,framerate=30/1*:**video/x-raw**(原始视频),**NV12**(**YUV 4:2:0**,单平面格式,常见于视频编码),分辨率 **1280×720(720p)**,帧率 **30fps**。 - *compression=ubwc,interlace-mode=progressive,colorimetry=bt601*:启用高通的 **UBWC(Ultra Bandwidth Compression)** 技术,通过硬件压缩减少内存带宽需求,逐行扫描(非隔行),色彩空间为 **ITU-R BT.601**(适用于标清视频)。 - *tee name=t*:分流器(**tee**)元素,作用是将一路输入数据复制成多路输出,方便对同一视频流进行多种不同处理(这里一路用于预览显示,一路用于编码存储)。**name=t** 给这个 **tee** 元素命名为 **t**,后续其他分支通过名字引用它来获取视频流。 - *queue ! waylandsink fullscreen=true*:**queue**:队列元素,用于在 **pipeline** 中创建一个缓冲队列,起到解耦上下游元素、异步处理的作用。可以缓解上下游处理速度不一致的问题,避免因一方处理慢导致另一方阻塞或丢帧。 **waylandsink**:输出 **sink** 元素,用于在 **Wayland** 显示服务器环境下,将视频画面渲染显示到屏幕上。 **fullscreen=true**:设置 **waylandsink** 以全屏模式显示视频画面。 - *t. ! queue*:**t.**:通过.语法引用之前命名为 **t** 的 **tee** 元素,获取视频流进行后续处理。 **queue**:再次使用队列元素,缓冲数据,保证编码等环节的流畅性。 - *v4l2h264enc capture-io-mode=5 output-io-mode=5 extra-controls="controls,video_bitrate=6000000 video_bitrate_mode=0;"* 使用 **DMABUF**(直接内存访问缓冲区)进行输入,优化数据传输效率,同样使用 **DMABUF** 输出编码后数据,目标比特率为 **6 Mbps**,使用 **CBR**(固定比特率)模式,适合网络流媒体或需要稳定带宽的场景。 - *queue ! h264parse ! mp4mux ! filesink location=/opt/mux_avc.mp4*:**queue**:又一个队列元素,继续缓冲编码后的数据,协调后续处理速度。解析 **H.264** 流,添加必要的 **NAL** 单元头部,使其符合 **MP4** 封装要求,将 **H.264** 视频流封装为 **MP4** 格式,将数据写入文件 **/opt/mux_avc.mp4**。 ### 预览+拍照 1. 在 **device** 终端中运行以下命令: ```shell gst-pipeline-app -e qtiqmmfsrc name=camsrc camera=1 ! 'video/x-raw(memory:GBM),format=NV12,width=1280,height=720,framerate=30/1' ! waylandsink camsrc.image_1 ! "image/jpeg,width=1280,height=720,framerate=30/1" ! multifilesink location=/opt/frame%d.jpg async=false sync=true ``` 2. 按 *Enter* 键。此命令将打印以下菜单并等待用户输入。 ```shell ##################################### MENU #####################################============================== Pipeline Controls==============================(0) NULL: Set the pipeline into NULL state (1) READY: Set the pipeline into READY state (2) PAUSED: Set the pipeline into PAUSED state (3) PLAYING: Set the pipeline into PLAYING state ==================================== Other====================================(p) Plugin Mode: Choose a plugin which to control (q) Quit : Exit the application Choose an option: ``` 3. 使用以下菜单步骤在预览时拍摄快照。 ```shell (1) ready -> (3) Playing -> (Enter)-> (p)Plugin Mode : Select (5)camerasrc ->(36) capture-image -> (1): still – Snapshot ->(1) Snapshot count ('guint' value for arg1) ``` 4. 要停止相机,请按 *Enter*,按 *b*(返回),然后按 *q*(退出)。拍摄的快照图像保存在 **/opt/** 中。通过在主机 **PC** 上运行以下 *scp* 命令,可以从设备中提取录制的内容: ```shell scp -r root@[ip-addr]:/opt/ . ``` - 生成文件如下图所示: ```{image} images/image_UZXdb8WaCo0PJGxTqFmczIk4nXf.webp :width: 369px :height: 34px ``` ### 双摄像头流拼接显示 从主摄像头和辅助摄像头获取的两个流(均为 **720p**)。两个流被发送以并排组合,然后显示。 ```shell gst-launch-1.0 -e qtivcomposer name=mixer sink_0::position="<0, 0>" sink_0::dimensions="<640, 360>" sink_1::position="<640, 0>" sink_1::dimensions="<640, 360>" mixer. ! queue ! waylandsink enable-last-sample=false fullscreen=true qtiqmmfsrc name=camsrc_0 camera=0 ! video/x-raw\(memory:GBM\), format=NV12, width=1280, height=720, framerate=30/1, compression=ubwc ! mixer. qtiqmmfsrc name=camsrc_1 camera=1 ! video/x-raw\(memory:GBM\), format=NV12, width=1280, height=720, framerate=30/1, compression=ubwc ! mixer. ``` - 如果要停止摄像头流,请按下 *CTRL+C*。 ## USB摄像头测试 **Quectel Pi H1** 智能主控板支持 **USB** 接口摄像头,下面选取微雪的一款 **OV5693 5MP USB** 接口摄像头为例进行测试。 ### 摄像头连接 将 **USB** 摄像头的连接线插入 **Quectel Pi H1** 的 **type-A** 接口。 ### 查看相关信息 1. 在 **SSH** 终端中运行以下命令,可查看系统识别到的 **USB** 设备信息: ```shell dmesg | grep usb ``` ```{image} images/image_I5RDbEiOtoWCP8xHw1ucDx7Dn5g.webp :width: 877px :height: 619px ``` 2. 在 **SSH** 终端中运行以下命令,可查看新增设备节点: ```shell v4l2-ctl --list-devices ``` ```{image} images/image_STXBbjVKJoUHwBxfaE1cbSF2n6e.webp :width: 876px :height: 273px ``` - /dev/video2 —— 主视频节点,后面gst命令主要操作这个节点 - /dev/video3 —— 元数据节点 - /dev/media3 —— 硬件拓扑控制器,控制整个pipeline 3. 在 **SSH** 终端中运行以下命令,可查看 **video** 节点支持的格式: ```shell v4l2-ctl --list-formats-ext --device /dev/video2 ``` ```{image} images/image_NeS9bxxKiotMoVxxCfrcAlZ9npc.webp :width: 876px :height: 588px ``` - 由图可知,该摄像头支持 **MJPG** 和 **YUYV** 两种格式的图片输出。 ### 前提条件 连接好 **HDMI** 屏幕,在 **SSH** 终端中运行以下命令: ```shell mount -o rw,remount / export XDG_RUNTIME_DIR=/dev/socket/weston export WAYLAND_DISPLAY=wayland-1 ``` ### 实时预览 1. 在 **device** 终端中运行以下命令: - MJPG格式(分辨率、帧率需符合摄像头支持的模式) ```shell gst-launch-1.0 v4l2src device=/dev/video2 ! image/jpeg,width=1280,height=720,framerate=30/1 ! jpegdec ! videoconvert ! waylandsink fullscreen=true ``` - YUYV格式(分辨率、帧率需符合摄像头支持的模式,GStreamer中使用YUY2表示此格式) ```shell gst-launch-1.0 v4l2src device=/dev/video2 ! video/x-raw,format=YUY2,width=1280,height=720,framerate=10/1 ! videoconvert ! waylandsink fullscreen=true ``` 命令说明: - gst-launch-1.0 -e 启动管线;**-e** 保证按 *Ctrl+C* 停止时能正确收尾(**EOS**)。 - v4l2src device=/dev/video2 从 **V4L2** 设备 **/dev/video2** 采集数据。 - image/jpeg,width=1280,height=720,framerate=30/1 要求摄像头输出 **1280×720@30 fps** 的 **MJPEG**;若摄像头不支持,**pipeline** 会直接报错。 - jpegdec 将 **MJPEG** 帧解码成原始 **YUV/RGB** 像素数据。 - videoconvert 把像素格式转成 **waylandsink** 能接受的格式(通常是 **NV12/BGRx**)。 - waylandsink fullscreen=true 用 **Wayland** 作为显示后端,并把窗口设置为全屏(无标题栏、铺满屏幕)。 ### 预览+视频录制 1. 在 **device** 终端中运行以下命令: ```shell gst-launch-1.0 -e v4l2src device=/dev/video2 io-mode=2 ! \ image/jpeg,width=1280,height=720,framerate=30/1 ! \ jpegdec ! videoconvert ! tee name=t \ t. ! queue ! v4l2h264enc ! h264parse ! mp4mux ! filesink location=/opt/out.mp4 \ t. ! queue ! videoconvert ! waylandsink fullscreen=true sync=false ``` 2. 此命令以 **720p 30 FPS** 配置启动相机,并在 **h264** 视频编码后将其另存为视频文件。如果 **gst** 管道状态更改为 **"PLAYING"**,则表示摄像头正在运行。 3. 如果要停止摄像头录制,请按下 *CTRL+C*。 4. **MP4** 文件保存在 **/opt/** 目录。 命令说明: - v4l2src device=/dev/video2 io-mode=2 从 **/dev/video2** 设备捕获视频流;**io-mode=2** 表示使用内存映射(**mmap**)模式,提高性能。 - image/jpeg,width=1280,height=720,framerate=30/1 指定捕获的视频流格式为 **MJPEG**,分辨率为 **1280×720**,帧率为 **30fps**。 - jpegdec 解码 **MJPEG** 格式的视频流,将其转换为原始的 **RGB/YUV** 格式。 - videoconvert 将解码后的视频格式转换为适合后续处理的格式(例如,从 **YUV** 转换为 **RGBA**)。 - tee name=t 将一路视频流分成两路,后续可以通过 **t.** 引用这两路流。 - t. ! queue 从 **tee** 元素中取出一路流,并通过 **queue** 元素进行缓冲。 - v4l2h264enc 将视频流编码为 **H.264** 格式。 - h264parse 解析 **H.264** 编码的视频流,使其符合 **MP4** 文件格式的要求。 - mp4mux 将 **H.264** 视频流封装为 **MP4** 文件格式。 - filesink location=/opt/out.mp4: 将封装好的 **MP4** 文件保存到 **/opt/out.mp4**。 - t. ! queue 从 **tee** 元素中取出另一路流,并通过 **queue** 元素进行缓冲。 - videoconvert 将视频格式转换为适合 **Wayland** 显示器显示的格式。 - waylandsink fullscreen=true sync=false 将视频流输出到 **Wayland** 显示器,以全屏模式显示视频,禁用同步模式,避免 **Wayland** 显示器等待数据流,从而提高显示性能。 5. 播放视频文件,请在 **device** 终端中运行以下命令: ```shell gst-launch-1.0 -e filesrc location=/opt/out.mp4 ! qtdemux ! queue ! h264parse ! v4l2h264dec capture-io-mode=5 output-io-mode=5 ! videocrop top=0 bottom=40 left=0 right=0 ! videoconvert ! waylandsink fullscreen=true enable-last-sample=false ``` 命令说明: - filesrc location=/opt/out.mp4 从 **/opt/out.mp4** 文件读取数据。 - qtdemux 将 **MP4** 文件中的视频和音频流分离出来。 - queue 缓冲数据,避免处理过程中的数据丢失。 - h264parse 解析视频流中的 **H.264** 编码数据。 - v4l2h264dec capture-io-mode=5 output-io-mode=5 使用 **V4L2** 解码器解码 **H.264** 视频流,**capture-io-mode=5** 和 **output-io-mode=5** 是硬件加速相关的参数。 - videocrop top=0 bottom=40 left=0 right=0 由于视频流自动对齐,填充额外的像素信息。导致视频底部有绿边,因此裁剪底部 **40** 像素。 - videoconvert 格式转换元素,确保裁剪后的视频流格式适合 **Wayland** 显示器。 - waylandsink fullscreen=true enable-last-sample=false 将解码后的视频输出到 **Wayland** 显示器上,并设置为全屏模式,同时禁用最后一帧显示。 ### 预览+拍照 1. 在 **device** 终端中运行以下命令: ```shell gst-launch-1.0 -e v4l2src device=/dev/video2 io-mode=2 ! \ image/jpeg,width=1280,height=720,framerate=30/1 ! \tee name=t \ t. ! queue ! jpegdec ! videoconvert ! waylandsink sync=false \ t. ! queue ! multifilesink location=/opt/shot-%05d.jpg max-files=5 ``` 2. 按下 *CTRL+C*,自动保存最后5张图片。 命令说明: - v4l2src device=/dev/video2 io-mode=2 从 **USB** 摄像头采集 **MJPEG** 数据。 - image/jpeg,width=1280,height=720,framerate=30/1 要求摄像头输出 **1280×720@30 fps** 的 **MJPEG** 流。 - tee name=t 把同一路流一分为多,后面用 **t.** 引用。 - t. ! queue ! jpegdec ! videoconvert ! waylandsink sync=false 预览分支:解码 **MJPEG** → 转成 **RGB** → 送到 **Wayland** 窗口实时显示。**sync=false** 减少延迟。 - t. ! queue ! multifilesink location=shot-%05d.jpg max-files=5 拍照分支:每一帧原封不动保存为 **JPG**,文件名自动编号 **%05d**(**5** 位数字)。**max-files=5** 只保留最近 **5** 张,旧文件被自动删除。 3. 查看照片请在 **device** 终端中输入以下命令: ```shell gst-launch-1.0 filesrc location=/opt/shot-00036.jpg ! jpegdec ! imagefreeze ! waylandsink fullscreen=true ``` 4. 退出查看,请按下 *CTRL+C*。 命令说明: - filesrc location=/opt/shot-00036.jpg 从文件系统读取 **/opt/shot-00036.jpg**。 - jpegdec 把 **JPEG** 压缩数据解码成原始 **RGB/YUV** 像素帧。 - imagefreeze 只保留第一帧,后续不断重复这一帧 → 实现“静止图片”效果。 - waylandsink fullscreen=true 把图像送到 **Wayland** 合成器全屏显示。 # 存储设备 ## NVMe SSD分区、格式化与挂载 本文介绍如何在Linux系统中对NVMe固态硬盘(以/dev/nvme0n1为例)进行分区、格式化、挂载及性能测试的完整流程。 ### 分区操作(使用fdisk) 通过fdisk工具对NVMe设备进行分区,步骤如下: #### 进入分区交互界面 执行以下命令,启动fdisk并指定目标NVMe设备: ```shell fdisk /dev/nvme0n1 ``` #### 交互界面操作步骤 进入fdisk交互模式后,按以下顺序执行命令: **创建GPT分区表** 输入 **g** 并回车,创建GUID分区表(GPT),适用于大容量设备(推荐): ```plaintext Command (m for help): g Created a new GPT disklabel (GUID: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX) ``` **新建分区** 输入 **n** 并回车,创建一个新分区。后续参数(分区号、起始扇区、结束扇区)保持默认即可(默认会使用全部可用空间): ```plaintext Command (m for help): n Partition number (1-128, default 1): First sector (2048-xxxxxxxxx, default 2048): Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-xxxxxxxxx, default xxxxxx): Created a new partition 1 of type 'Linux filesystem' and of size XX GiB. ``` **写入分区表并退出** 输入 **w** 并回车,将分区配置写入设备并退出fdisk: ```plaintext Command (m for help): w The partition table has been altered. Calling ioctl() to re-read partition table. Syncing disks. ``` 操作完成后,系统会生成新分区/dev/nvme0n1p1(p1表示第一个分区)。 ### 格式化分区(EXT4格式) 使用mkfs.ext4工具将新分区格式化为EXT4文件系统(适用于大多数Linux环境): ```shell mkfs.ext4 /dev/nvme0n1p1 ``` 执行后会显示格式化进度,完成后输出类似信息: ```plaintext mke2fs 1.46.5 (30-Dec-2021) Creating filesystem with 12345678 4k blocks and 3456789 inodes Filesystem UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Superblock backups stored on blocks: 32768, 98304, 163840, ... Allocating group tables: done Writing inode tables: done Creating journal (65536 blocks): done Writing superblocks and filesystem accounting information: done ``` ### 手动挂载分区 #### 创建挂载目录 使用mkdir命令创建一个用于挂载SSD的目录(示例路径为/mnt/myssd): ```shell mkdir -p /mnt/myssd ``` #### 挂载分区 将/dev/nvme0n1p1分区挂载到/mnt/myssd目录: ```shell mount /dev/nvme0n1p1 /mnt/myssd ``` 可通过 **df -h** 命令验证挂载是否成功,若输出中包含/dev/nvme0n1p1和/mnt/myssd则表示挂载正常: ```shell df -h Filesystem Size Used Avail Use% Mounted on /dev/nvme0n1p1 100G 5G 95G 5% /mnt/myssd ``` ### 配置自动挂载(重启后生效) 通过修改/etc/fstab文件实现系统启动时自动挂载分区: #### 编辑fstab文件 使用编辑器打开/etc/fstab: #### 添加挂载配置 在文件末尾添加以下行,指定分区、挂载点、文件系统类型及挂载参数: ```plaintext /dev/nvme0n1p1 /mnt/myssd ext4 defaults 0 2 ``` ### 性能测试(读写速度验证) 使用dd命令测试SSD的读写性能(测试时确保分区已挂载): #### 读取速度测试 创建一个临时测试文件(若已存在),并通过读取该文件到空设备(/dev/null)测试读取速度: ```shell dd if=/mnt/myssd/testfile of=/dev/null bs=1G iflag=direct ``` **说明**:*iflag=direct* 表示绕过系统缓存,测试真实读取速度。 输出示例: ```plaintext 1+0 records in 1+0 records out 1073741824 bytes (1.1 GB, 1.0 GiB) copied, 0.852345 s, 1.3 GB/s ``` #### 写入速度测试 生成一个1 GB的空文件(/dev/zero为零数据来源),测试写入速度: ```shell dd if=/dev/zero of=/mnt/myssd/testfile bs=1G count=1 oflag=direct ``` 输出示例: ```plaintext 1+0 records in 1+0 records out 1073741824 bytes (1.1 GB, 1.0 GiB) copied, 1.245678 s, 862 MB/s ``` 测试完成后可删除临时文件: ```shell rm /mnt/myssd/testfile ``` ## UFS存储 Quectel Pi H1内嵌128 GB UFS存储芯片。相较于eMMC,其UFS读写速度更快、支持全双工通信和命令队列,性能更优。 ### 查看容量 通过fdisk -l命令可以查询到UFS分区信息及容量。 ```shell root@qcm6490-idp:/opt/bc-1.08.1# fdisk -l Disk /dev/sda: 116.09 GiB, 124646326272 bytes, 30431232 sectors Disk model: C2G072 Units: sectors of 1 * 4096 = 4096 bytes Sector size (logical/physical): 4096 bytes / 4096 bytes I/O size (minimum/optimal): 4096 bytes / 4096 bytes Disklabel type: gpt Disk identifier: 49B3A77D-3D7D-22A5-0A10-6A2ECDDEA256 Device Start End Sectors Size Type /dev/sda1 6 131077 131072 512M EFI System /dev/sda2 131078 138757 7680 30M Linux filesystem /dev/sda3 138758 30431226 30292469 115.6G Linux root (ARM-64) ``` ### 查看分区信息 通过df命令可以查询到UFS分区信息,使用情况,挂载目录等信息。 ```shell root@qcm6490-idp:/opt/bc-1.08.1# df -h Filesystem Size Used Avail Use% Mounted on /dev/sda3 109G 3.3G 101G 4% /sysroot devtmpfs 4.0M 0 4.0M 0% /dev tmpfs 3.6G 0 3.6G 0% /dev/shm tmpfs 1.5G 31M 1.5G 3% /run tmpfs 4.0M 0 4.0M 0% /sys/fs/cgroup tmpfs 3.6G 12K 3.6G 1% /tmp tmpfs 3.6G 0 3.6G 0% /var/volatile /dev/sda1 511M 136M 376M 27% /boot /dev/sda2 25M 892K 22M 4% /var/persist tmpfs 737M 0 737M 0% /run/user/0 ``` ### 性能测试 性能测试主要测试ufs在linux系统下对文件的读写速度,一般结合 *time* 与 *dd* 双命令进行测试。 **写文件测试** ```shell root@qcm6490-idp:/opt# time dd if=/dev/zero of=tempfile bs=1M count=100 conv=fdatasync100+0 records in100+0 records out 104857600 bytes (105 MB, 100 MiB) copied, 0.2874 s, 365 MB/s real 0m0.316s user 0m0.000s sys 0m0.122s ``` 使用 *dd* 命令写文件时,需要加 *conv=fdatasync* 参数,表示当 *dd* 完成写入操作后,会强制将缓存中的数据同步到磁盘。因为对磁盘的写操作一般是先写到内核缓存(page cache),系统调用就立即返回成功,但数据可能还没有真正写入物理磁盘。使用 *conv=fdatasync* 可以确保数据真正写入磁盘后才返回,这样测试出的速度才是真实的磁盘写入速度。这里测试出写磁盘速度为365 MB/s。 **读文件测试** 在嵌入式系统中,经常需要测试系统文件读写性能。读文件时,系统默认会使用cache(缓存),这会导致测试结果不准确,因为从cache读取数据的速度远快于从磁盘读取。为了测试真实的磁盘读取速度,需要忽略cache的影响,可以指定参数iflag=direct,nonblock。 ```shell root@qcm6490-idp:/opt# time dd if=tempfile of=/dev/null bs=1M count=100 iflag=direct,nonblock100+0 records in100+0 records out 104857600 bytes (105 MB, 100 MiB) copied, 0.196993 s, 532 MB/s real 0m0.201s user 0m0.001s sys 0m0.041s ``` 可知,从磁盘直接读取读速度为532 MB/s。 # 核心资源与性能 ## CPU指标与测试 **Quectel Pi H1** 智能主控板采用高通QCS6490作为核心处理器,基于Arm v8 Cortex,主频高达2.7 GHz。 1. **查看CPU信息命令** ```plaintext root@qcm6490-idp:/# cat /proc/cpuinfo processor : 0 BogoMIPS : 38.40 Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm lrcpc dcpop asimddp CPU implementer : 0x41 CPU architecture: 8 CPU variant : 0x2 CPU part : 0xd05 CPU revision : 0 processor : 1 BogoMIPS : 38.40 Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm lrcpc dcpop asimddp CPU implementer : 0x41 CPU architecture: 8 CPU variant : 0x2 CPU part : 0xd05 CPU revision : 0 ``` - processor:系统中逻辑处理核的编号,对于多核处理器则可以是物理核、或者使用超线程技术虚拟的逻辑核 - BogoMIPS:在系统内核启动时粗略测算的CPU每秒运行百万条指令数(Million Instructions Per Second) 2. **查看CPU使用率** 执行 **top** 之后,按 **1** 显示各CPU核使用率 ```plaintext root@qcm6490-idp:/# top top - 00:20:05 up 20 min, 1 user, load average: 0.04, 0.07, 0.06 Tasks: 340 total, 1 running, 339 sleeping, 0 stopped, 0 zombie %Cpu0 : 0.5 us, 1.6 sy, 0.0 ni, 97.3 id, 0.0 wa, 0.5 hi, 0.0 si, 0.0 st %Cpu1 : 0.5 us, 0.0 sy, 0.0 ni, 98.9 id, 0.0 wa, 0.5 hi, 0.0 si, 0.0 st %Cpu2 : 1.6 us, 0.0 sy, 0.0 ni, 97.3 id, 0.5 wa, 0.0 hi, 0.0 si, 0.5 st %Cpu3 : 0.0 us, 0.5 sy, 0.0 ni, 98.4 id, 0.0 wa, 0.5 hi, 0.0 si, 0.5 st %Cpu4 : 1.1 us, 0.0 sy, 0.0 ni, 98.4 id, 0.0 wa, 0.0 hi, 0.0 si, 0.5 st %Cpu5 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st %Cpu6 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st %Cpu7 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st MiB Mem : 7366.7 total, 6386.2 free, 498.6 used, 481.9 buff/cache MiB Swap: 5395.5 total, 5395.5 free, 0.0 used. 6698.9 avail Mem PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 1 root 20 0 162028 9468 6524 S 1.1 0.1 0:07.64 systemd 594 message+ 20 0 6904 3712 3328 S 1.1 0.0 0:06.46 dbus-daemon 1087 root 20 0 1794556 61472 30848 S 1.1 0.8 0:05.56 containerd 1816 root 20 0 5768 2688 2048 R 1.1 0.0 0:00.04 top 40 root 20 0 0 0 0 I 0.5 0.0 0:00.48 kworker/3:0-mm_percpu_wq 50 root 20 0 0 0 0 S 0.5 0.0 0:00.55 rcuop/4 127 root 20 0 0 0 0 I 0.5 0.0 0:00.47 kworker/u16:6-events_unbound 280 root 20 0 34988 15176 14792 S 0.5 0.2 0:05.38 systemd-journal 925 root 20 0 630136 72200 53256 S 0.5 1.0 0:06.65 weston ``` - %us:表示用户空间程序的CPU使用率(没有通过nice调度) - %sy:表示系统空间的CPU使用率,主要是内核程序 - %ni:表示通过nice调度过的用户空间程序的CPU使用率 - %id:空闲CPU - %wa: 等待输入输出的CPU时间百分比 - %hi: CPU处理硬中断的数量 - %si: CPU处理软中断的数量 - %st: 实时 3. **获取CPU温度信息** ```plaintext root@qcm6490-idp:/# cat /sys/class/thermal/thermal_zone0/temp 37000 ``` - 上述显示数字为千分之一度,除以1000就是当前温度值(单位:摄氏度)。 4. **CPU压力测试** CPU压力的测试方式有很多,可通过bc命令来计算圆周率方法来测试CPU在运算过程中的稳定性。 ```plaintext root@qcm6490-idp:/# echo "scale=5000; 4*a(1)" | bc -l -q & [1] 1592 ``` 上述命令将在后台计算PI,并精确到小数点后5000位,计算过程需要一段时间。 此时,我们可以通过top命令检查CPU利用率的变化,如下所示: ```plaintext root@qcm6490-idp:/# top top - 06:42:14 up 8 min, 1 user, load average: 0.29, 0.16, 0.09 Tasks: 326 total, 3 running, 323 sleeping, 0 stopped, 0 zombie %Cpu(s): 12.7 us, 0.2 sy, 0.0 ni, 86.8 id, 0.0 wa, 0.1 hi, 0.0 si, 0.2 st MiB Mem : 7366.9 total, 6540.2 free, 439.5 used, 387.2 buff/cache MiB Swap: 5395.7 total, 5395.7 free, 0.0 used. 6770.1 avail Mem PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 1592 root 20 0 3052 1792 1536 R 99.7 0.0 0:14.37 bc 588 message+ 20 0 6908 3584 3200 S 0.7 0.0 0:03.06 dbus-da+ 1 root 20 0 162064 9324 6380 S 0.3 0.1 0:04.26 systemd ... ``` 约15秒后,PI结果被计算出来。在此期间CPU使用率达到100%,没有发生异常,说明CPU压力测试通过。还可以继续增加精确值,可进一步提高CPU压力测试强度。 ```plaintext root@qcm6490-idp:/# 3.141592653589793238462643383279502884197169399375105820974944592307\ 81640628620899862803482534211706798214808651328230664709384460955058\ 22317253594081284811174502841027019385211055596446229489549303819644\ ... ``` ## Memory状态 1. **查看内存信息** ```shell root@qcm6490-idp:/opt/bc-1.08.1# cat /proc/meminfo MemTotal: 7543736 kB MemFree: 6664720 kB MemAvailable: 6928688 kB Buffers: 19768 kB Cached: 380520 kB SwapCached: 0 kB Active: 52044 kB Inactive: 462332 kB Active(anon): 3588 kB Inactive(anon): 142568 kB Active(file): 48456 kB Inactive(file): 319764 kB ``` - MemTotal:所有可用的RAM大小,物理内存减去预留位和内核使用 - MemFree:LowFree + HighFree - Buffers:用来给块设备做缓存的大小 - Cached:文件的缓冲区大小 - SwapCached:已经被交换出来的内存。与I/O相关 - Active:经常(最近)被使用的内存 - Inactive:最近不常使用的内存 2. **获取内存使用率** ```shell root@qcm6490-idp:/opt/bc-1.08.1# free -m total used free shared buff/cache available Mem: 7366 437 6504 31 424 6763 Swap: 5395 0 5395 ``` - total:内存总量 - used:被使用的内存量 - free:可使用的内存量 3. **内存压力测试** 通过给定测试内存的大小和次数, 可以对系统现有的内存进行压力上的测试。可使用系统工具memtester进行测试,如指定内存大小300 MB,测试次数为1,测试命令为"memtester 300M 1"。 下列以使用300 MB内存空间,单次测试为例: ```shell root@qcm6490-idp:/# memtester 300M 1 memtester version 4.5.1 (64-bit) Copyright (C) 2001-2020 Charles Cazabon. Licensed under the GNU General Public License version 2 (only). pagesize is 4096 pagesizemask is 0xfffffffffffff000 want 300MB (314572800 bytes) got 300MB (314572800 bytes), trying mlock ...locked. Loop 1/1: Stuck Address : ok Random Value : ok Compare XOR : ok Compare SUB : ok Compare MUL : ok Compare DIV : ok Compare OR : ok Compare AND : ok Sequential Increment: ok Solid Bits : ok Block Sequential : ok Checkerboard : ok Bit Spread : ok Bit Flip : ok Walking Ones : ok Walking Zeroes : ok Done. ``` # 电源与功耗 ## PMIC休眠唤醒 Linux内核一般提供了几种Suspend模式:Freeze(对应"freeze")、Standby(对应"standby")、STR(Suspend to RAM,对应"mem")和STD(Suspend to Disk,对应"disk")。在用户空间向/sys/power/state文件写入对应的字符串即可触发相应的休眠模式。**Quectel Pi H1** 支持freeze和mem两种方式,standby和disk暂不支持。以下将以mem为例进行测试说明。 - 查看当前Quectel Pi H1支持的模式 ```plaintext root@qcm6490-idp:/# cat /sys/power/state freeze mem disk ``` - 设置唤醒源 测试休眠唤醒需要先设置唤醒源,设置Debug串口(ttySC0)为唤醒源。 ```plaintext root@qcm6490-idp:/# echo enabled > /sys/devices/platform/soc@0/9c0000.geniqup/994000.serial/tty/ttyMSM0/power/wakeup ``` - 休眠到内存 在用户空间向/sys/power/state写入字符串即进入相应的电源管理模式,休眠到内存的方式如下: ```plaintext root@qcm6490-idp:/# echo mem > /sys/power/state [15219.746797] PM: suspend entry (s2idle) [15219.760424] Filesystems sync: 0.013 seconds [15219.780574] Freezing user space processes [15219.781589] process_accept_req: 22 callbacks suppressed [15219.781600] smcinvoke: process_accept_req: Server id :17 interrupted probaby due to suspend, pid:897 [15219.791806] smcinvoke: process_accept_req: Server id :24 interrupted probaby due to suspend, pid:962 [15219.801969] smcinvoke: process_accept_req: Server id :18 interrupted probaby due to suspend, pid:903 [15219.812240] smcinvoke: process_accept_req: Server id :17 interrupted probaby due to suspend, pid:898 [15219.822590] smcinvoke: process_accept_req: Server id :18 interrupted probaby due to suspend, pid:902 [15219.832962] smcinvoke: process_accept_req: Server id :26 interrupted probaby due to suspend, pid:969 [15219.843391] smcinvoke: process_accept_req: Server id :21 interrupted probaby due to suspend, pid:929 [15219.853728] smcinvoke: process_accept_req: Server id :21 interrupted probaby due to suspend, pid:930 [15219.864031] smcinvoke: process_accept_req: Server id :17 interrupted probaby due to suspend, pid:899 [15219.874482] smcinvoke: process_accept_req: Server id :22 interrupted probaby due to suspend, pid:935 [15219.900228] Freezing user space processes completed (elapsed 0.119 seconds) ``` - **通过Debug串口唤醒** 输入休眠命令后Quectel Pi H1休眠,将运行状态数据存到内存,并关闭外设,进入等待模式,此时因为设置的是debug唤醒,键盘随意输入字符即能成功唤醒系统,如下: ```plaintext [15221.270632] process_accept_req: 3 callbacks suppressed [15221.270636] smcinvoke: process_accept_req: process_accept_req txn 4 either invalid or removed from Q [15221.270655] smcinvoke: process_accept_req: process_accept_req txn 2 either invalid or removed from Q [15221.270668] smcinvoke: process_accept_req: process_accept_req txn 3 either invalid or removed from Q [15221.270742] smcinvoke: process_accept_req: process_accept_req txn 2 either invalid or removed from Q [15221.270870] smcinvoke: process_accept_req: process_accept_req txn 1 either invalid or removed from Q [15221.270924] smcinvoke: process_accept_req: process_accept_req txn 4 either invalid or removed from Q [15221.270981] smcinvoke: process_accept_req: process_accept_req txn 3 either invalid or removed from Q [15221.270982] done. [15221.271044] smcinvoke: process_accept_req: process_accept_req txn 1 either invalid or removed from Q [15221.271059] smcinvoke: process_accept_req: process_accept_req txn 3 either invalid or removed from Q [15221.271078] smcinvoke: process_accept_req: process_accept_req txn 2 either invalid or removed from Q [15221.371963] PM: suspend exit ``` # USB与扩展外设 ## USB Host测试 USB Host是指能够控制和管理USB设备的系统或硬件,它负责为连接的USB设备(如U盘、键盘、鼠标等)提供电源、数据传输和管理功能。以下是一些常见的USB Host的功能和应用场景。 插入示例: ```{image} images/image_SOMRbgocEohoM5xrTCQcsBktndg.webp :width: 916px :height: 685px ``` ### U盘挂载 当U盘插入到Quectel Pi H1上的USB Host上时,系统检测到一个USB闪存盘,并已成功初始化为存储设备。通过dmesg -n 8查看日志: ```plaintext usb 1-1.2: new high-speed USB device number 7 using xhci-hcd [ 806.667878][ T162] usb-storage 1-1.2:1.0: USB Mass Storage device detected [ 806.676812][ T162] scsi host1: usb-storage 1-1.2:1.0 [ 808.172742][ T162] scsi 1:0:0:0: Direct-Access USB Flash Disk 1100 PQ: 0 ANSI: 4 [ 808.189763][ T74] sd 1:0:0:0: [sdg] 15730688 512-byte logical blocks: (8.05 GB/7.50 GiB) [ 808.200512][ T74] sd 1:0:0:0: [sdg] Write Protect is off [ 808.207624][ T74] sd 1:0:0:0: [sdg] Mode Sense: 43 00 00 00 [ 808.216028][ T74] sd 1:0:0:0: [sdg] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA [ 808.244091][ T74] sdg: sdg1 ``` - 确认设备节点 ```bash lsblk ``` 输出信息如下: ```plaintext NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS sda 8:0 0 116.1G 0 disk |-sda1 8:1 0 512M 0 part /boot |-sda2 8:2 0 30M 0 part /var/persist `-sda3 8:3 0 115.6G 0 part /var /usr / /sysroot sdb 8:16 0 8M 0 disk |-sdb1 8:17 0 3.5M 0 part |-sdb2 8:18 0 512K 0 part `-sdb3 8:19 0 3.5M 0 part sdc 8:32 0 8M 0 disk |-sdc1 8:33 0 3.5M 0 part |-sdc2 8:34 0 512K 0 part `-sdc3 8:35 0 3.5M 0 part sdd 8:48 0 32M 0 disk |-sdd1 8:49 0 104K 0 part |-sdd2 8:50 0 128K 0 part |-sdd3 8:51 0 1M 0 part |-sdd4 8:52 0 1M 0 part `-sdd5 8:53 0 1M 0 part sde 8:64 0 3G 0 disk |-sde1 8:65 0 512K 0 part |-sde2 8:66 0 64M 0 part |-sde3 8:67 0 256K 0 part |-sde4 8:68 0 2M 0 part |-sde5 8:69 0 5M 0 part |-sde6 8:70 0 4M 0 part |-sde7 8:71 0 8M 0 part |-sde8 8:72 0 4M 0 part |-sde9 8:73 0 32M 0 part |-sde10 8:74 0 128K 0 part |-sde11 8:75 0 80K 0 part |-sde12 8:76 0 2M 0 part |-sde13 8:77 0 2M 0 part |-sde14 8:78 0 128K 0 part |-sde15 8:79 0 32K 0 part |-sde16 259:0 0 1M 0 part |-sde17 259:1 0 256K 0 part |-sde18 259:2 0 512K 0 part |-sde19 259:3 0 256K 0 part |-sde20 259:4 0 64M 0 part |-sde21 259:5 0 2M 0 part |-sde22 259:6 0 5M 0 part |-sde23 259:7 0 4M 0 part |-sde24 259:8 0 8M 0 part |-sde25 259:9 0 4M 0 part |-sde26 259:10 0 32M 0 part |-sde27 259:11 0 128K 0 part |-sde28 259:12 0 80K 0 part |-sde29 259:13 0 2M 0 part |-sde30 259:14 0 2M 0 part |-sde31 259:15 0 128K 0 part |-sde32 259:16 0 32K 0 part |-sde33 259:17 0 1M 0 part |-sde34 259:18 0 256K 0 part |-sde35 259:19 0 4K 0 part |-sde36 259:20 0 4K 0 part |-sde37 259:21 0 4K 0 part |-sde38 259:22 0 16M 0 part |-sde39 259:23 0 30M 0 part |-sde40 259:24 0 1M 0 part |-sde41 259:25 0 32.6M 0 part |-sde42 259:26 0 4K 0 part |-sde43 259:27 0 4K 0 part |-sde44 259:28 0 1M 0 part |-sde45 259:29 0 8M 0 part |-sde46 259:30 0 40M 0 part |-sde47 259:31 0 512M 0 part |-sde48 259:32 0 28K 0 part |-sde49 259:33 0 512K 0 part |-sde50 259:34 0 1M 0 part `-sde51 259:35 0 32.6M 0 part sdf 8:80 0 32M 0 disk |-sdf1 8:81 0 3M 0 part |-sdf2 8:82 0 3M 0 part |-sdf3 8:83 0 3M 0 part `-sdf4 8:84 0 128K 0 part sdg 8:96 1 7.5G 0 disk `-sdg1 8:97 1 7.5G 0 part zram0 253:0 0 5.3G 0 disk [SWAP] ``` - 创建挂载点 ```bash mkdir -p /mnt/usb ``` - 挂载分区 ```bash mount /dev/sdg1 /mnt/usb ``` - 验证挂载 ```bash df -h ``` 输出信息如下: ```plaintext Filesystem Size Used Avail Use% Mounted on /dev/sda3 109G 3.3G 101G 4% /sysroot devtmpfs 4.0M 0 4.0M 0% /dev tmpfs 3.6G 0 3.6G 0% /dev/shm tmpfs 1.5G 19M 1.5G 2% /run tmpfs 4.0M 0 4.0M 0% /sys/fs/cgroup tmpfs 3.6G 20K 3.6G 1% /tmp tmpfs 3.6G 0 3.6G 0% /var/volatile /dev/sda1 511M 136M 376M 27% /boot /dev/sda2 25M 44K 22M 1% /var/persist tmpfs 737M 0 737M 0% /run/user/0 /dev/sdg1 7.5G 1.9G 5.7G 25% /var/rootdirs/mnt/usb ``` - 访问U盘内容 ```bash ls /mnt/usb ``` - 卸载U盘 ```bash umount /mnt/usb ``` ### 键盘、鼠标 当Logitech USB无线接收器插入到Quectel Pi H1上的USB Host上时,键盘鼠标可以正常使用。具体细节可以通过 **dmesg -n 8** 查看日志,显示了一个Logitech USB无线接收器(型号046D:C534,罗技键盘/鼠标套装)被Linux系统成功识别并初始化的过程。 ```plaintext usb 1-1.1: new full-speed USB device number 6 using xhci-hcd [ 478.273171][ T1373] input: Logitech USB Receiver as /devices/platform/soc@0/8c00000.usb/xhci-hcd.0.auto/usb1/1-1/1-1.1/1-1.1:1.0/0003:046D:C534.0003/input/input10 [ 478.350114][ T1373] hid-generic 0003:046D:C534.0003: input: USB HID v1.11 Keyboard [Logitech USB Receiver] on usb-xhci-hcd.0.auto-1.1/input0 [ 478.367447][ T1373] input: Logitech USB Receiver Mouse as /devices/platform/soc@0/8c00000.usb/xhci-hcd.0.auto/usb1/1-1/1-1.1/1-1.1:1.1/0003:046D:C534.0004/input/input11 [ 478.383765][ T1373] input: Logitech USB Receiver Consumer Control as /devices/platform/soc@0/8c00000.usb/xhci-hcd.0.auto/usb1/1-1/1-1.1/1-1.1:1.1/0003:046D:C534.0004/input/input12 [ 478.458989][ T1373] input: Logitech USB Receiver System Control as /devices/platform/soc@0/8c00000.usb/xhci-hcd.0.auto/usb1/1-1/1-1.1/1-1.1:1.1/0003:046D:C534.0004/input/input13 [ 478.475639][ T1373] hid-generic 0003:046D:C534.0004: input,hiddev96: USB HID v1.11 Mouse [Logitech USB Receiver] on usb-xhci-hcd.0.auto-1.1/input1 ``` ## USB OTG测试 利用 **qusb** 命令设置 **USB** 工作模式,**qusb** 支持的参数如下: ```plaintext init 初始化USB配置(挂载configfs,创建设备节点,加载默认PID) bind 绑定USB设备到配置(激活当前配置) unbind 解绑USB设备(停止当前配置) setpid 切换到指定PID的USB组合模式(如setpid 901D启用DIAG+ADB) setpid -p 设置PID为默认模式(持久化到/etc/usb/usb_pid,重启后生效) showpid 显示所有支持的PID及其对应功能组合 persist 仅持久化PID(不立即切换) ``` ### 利用qusb测试USB口模拟网卡的功能 - 查看 **usb** 支持的所有功能: ```shell root@qcm6490-idp:/# qusb showpid A4A1: NCM 4EE7: ADB 900E: DIAG 901C: DIAG,UAC2 901D: DIAG,ADB 9015: MASS_STORAGE,ADB 9024: RNDIS,ADB 902A: RNDIS,MASS_STORAGE 902B: RNDIS,ADB,MASS_STORAGE 902C: RNDIS,DIAG 902D: RNDIS,DIAG,ADB 902F: RNDIS,DIAG,MASS_STORAGE 908C: NCM,ADB 90CA: DIAG,UAC2,ADB 90CB: DIAG,UVC,ADB 90CC: DIAG,UAC2,UVC,ADB 90DF: DIAG,UVC 90E0: DIAG,UAC2,UVC 9135: DIAG,QDSS,ADB 9136: DIAG,QDSS F000: MASS_STORAGE F00E: RNDIS ``` - 切换 **USB** 模式:*qusb setpid 908C* # 启用 **NCM+ADB**,此时在设备的 **Shell** 里执行 *ifconfig -a* 可以查看到 **usb0** 接口 - 将 **Quectel Pi H1** 的 **Type-C** 口与 **PC** 的 **USB** 口连接[**PC** 的系统建议是 **linux**] - 为 **Quectel Pi H1** 的 **usb0** 接口设置 **IP** 地址:*ip addr add dev usb0 192.168.0.5/24* - 为 **PC** 上新识别出来的 **USB** 网卡设置地址:*ip addr add dev enp0s20f0u13 192.168.0.6/24* # 这里的 **enp0s20f0u13** 需要根据实际情况进行修改 - 测试网络:在 **PC** 的 **Shell** 中执行 *ping 192.168.0.5* #可以观察到能程序 **ping** 通目的地址 ### 连接Wi-Fi的一般步骤及示例 ## 打开Wi-Fi功能 使用命令来打开Wi-Fi功能,相当于桌面版的“打开Wi-Fi开关”。 ```shell nmcli radio wifi on ``` ## 查看可用Wi-Fi列表 执行命令,扫描并列出当前无线网卡探测到的Wi-Fi网络。该命令会显示附近的Wi-Fi网络以及它们的名称(SSID)、信号强度、频道和加密方式等信息。 ```shell nmcli dev wifi list ifname wlan0 ``` 返回如下,可以看到周围的热点信息。 ```shell root@qcm6490-idp:~# nmcli dev wifi list ifname wlan0 IN-USE BSSID SSID MODE CHAN RATE SIGNAL BARS SECURITY 64:09:80:76:42:BE Xiaomi_42BD Infra 11 130 Mbit/s 100 ▂▄▆█ WPA1 WPA2 * F8:5E:3C:01:F8:18 xiupax Infra 11 130 Mbit/s 100 ▂▄▆█ -- 9C:9D:7E:F7:30:5E tdz Infra 2 130 Mbit/s 97 ▂▄▆█ WPA1 WPA2 E2:F1:E1:57:D5:C6 gms-wifi Infra 1 0 Mbit/s 95 ▂▄▆█ WPA1 WPA2 E2:F1:E1:57:D5:C8 cit-test-5g Infra 1 0 Mbit/s 94 ▂▄▆█ WPA2 48:5F:08:BB:BA:41 TP-LINK_BA41 Infra 11 270 Mbit/s 87 ▂▄▆█ -- 64:09:80:76:42:BF Xiaomi_42BD_5G Infra 157 270 Mbit/s 82 ▂▄▆█ WPA1 WPA2 B4:2F:03:DA:23:B5 5G_RRO_A23B5 Infra 157 135 Mbit/s 79 ▂▄▆_ WPA1 WPA2 A2:A7:90:A7:5B:A0 LSMate30 Infra 149 270 Mbit/s 77 ▂▄▆_ WPA2 A4:00:E2:EF:F7:83 Quectel-HF Infra 1 260 Mbit/s 74 ▂▄▆_ WPA1 WPA2 802.1X F0:2F:74:2A:41:78 odmtest Infra 1 260 Mbit/s 74 ▂▄▆_ WPA3 2C:CF:67:6B:4A:86 HW-676B4A85 Infra 36 117 Mbit/s 74 ▂▄▆_ WPA1 A4:00:E2:EF:F7:82 Quectel-HF-2.4G Infra 1 260 Mbit/s 72 ▂▄▆_ WPA1 WPA2 802.1X A4:00:E2:EF:F7:80 Quectel-Customer-2.4G Infra 1 260 Mbit/s 72 ▂▄▆_ WPA1 WPA2 66:D6:9A:C6:6D:21 PAXWIFIAP_2.4G Infra 1 130 Mbit/s 72 ▂▄▆_ WPA2 A4:00:E2:EF:F7:90 Quectel-Customer Infra 44 540 Mbit/s 72 ▂▄▆_ WPA1 WPA2 A4:00:E2:EF:F7:92 Quectel-HF Infra 44 540 Mbit/s 72 ▂▄▆_ WPA1 WPA2 802.1X 9C:9D:7E:F7:30:5F tdz Infra 149 270 Mbit/s 70 ▂▄▆_ WPA1 WPA2 34:CE:00:09:E5:A8 SW_test Infra 6 130 Mbit/s 69 ▂▄▆_ WPA1 WPA2 E2:F1:E1:57:D5:CA gms-wifi_5G Infra 149 270 Mbit/s 69 ▂▄▆_ WPA1 WPA2 E2:F1:E1:57:D5:CE cit-test-5g Infra 149 270 Mbit/s 69 ▂▄▆_ WPA2 F0:2F:74:2A:41:7C odmtest-5G Infra 161 540 Mbit/s 65 ▂▄▆_ WPA2 A4:00:E2:EF:F8:52 Quectel-HF Infra 36 540 Mbit/s 57 ▂▄▆_ WPA1 WPA2 802.1X A4:00:E2:EF:F8:50 Quectel-Customer Infra 36 540 Mbit/s 57 ▂▄▆_ WPA1 WPA2 3C:7C:3F:0B:94:FC HWTEST Infra 161 540 Mbit/s 52 ▂▄__ WPA2 A4:00:E2:EF:F4:50 Quectel-Customer Infra 149 540 Mbit/s 49 ▂▄__ WPA1 WPA2 A4:00:E2:EF:F4:52 Quectel-HF Infra 149 540 Mbit/s 47 ▂▄__ WPA1 WPA2 802.1X ``` ## 连接Wi-Fi网络 选择要连接的Wi-Fi网络,并执行命令 **nmcli dev wifi connect "你的Wi-Fi名称" password "你的密码"** 来连接到该网络。例如,**nmcli dev wifi connect "MyHomeWiFi" password "12345678"**。如果网络没有密码,则不需要提供password参数。 连接加密热点: ```shell root@qcm6490-idp:~# nmcli dev wifi connect "SSID" password "12345678" ifname wlan0 Device 'wlan0' successfully activated with 'd0ef4183-ac40-41d5-8822-2cc174107c77'. ``` 连接开放热点: ```shell root@qcm6490-idp:~# nmcli dev wifi connect "SSID" ifname wlan0 Device 'wlan0' successfully activated with 'd0ef4183-ac40-41d5-8822-2cc174107c77'. ``` 使用 **ifconfig** 命令查看网络接口地址: ```shell root@qcm6490-idp:~# ifconfig eth0 Link encap:Ethernet HWaddr 32:C0:A2:09:FE:40 UP BROADCAST MULTICAST MTU:1500 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) Interrupt:167 Base address:0x1000 lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:65536 Metric:1 RX packets:75 errors:0 dropped:0 overruns:0 frame:0 TX packets:75 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:6301 (6.1 KiB) TX bytes:6301 (6.1 KiB) p2p0 Link encap:Ethernet HWaddr 02:03:7F:D6:00:01 UP BROADCAST MULTICAST MTU:1500 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:3000 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) wlan0 Link encap:Ethernet HWaddr 00:03:7F:50:00:01 inet addr:192.168.253.211 Bcast:192.168.253.255 Mask:255.255.255.0 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:3421 errors:0 dropped:0 overruns:0 frame:0 TX packets:61 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:3000 RX bytes:151273 (147.7 KiB) TX bytes:7300 (7.1 KiB) ``` 可以发现wlan0口已经获取IP。 #### 测试无线网络 执行 **ping** 命令测试网络连接: - 执行 *ping 192.168.1.1* 命令,如果 **ping** 通则表示局域网网络连接正常【这里的目的 **ip** 需要修改为实际网络的网关地址】。 - 执行 *ping 114.114.114.114* 命令,如果 **ping** 通则表示外部网络连接正常。 - 执行 *ping baidu.com* 命令,如果 **ping** 通则表示外部网络连接正常且 **DNS** 解析功能正常。